Solved

Mid Function of VB6 in C++

Posted on 2009-04-12
14
1,209 Views
Last Modified: 2012-05-06
Dear All,

I am trying to develop a code similar to VB6's mid function. The mid function returns a given number of characters from the middle of a string

Usage

Mid(string, start, length)

string = string to use
start = character to start at (1 is the first character)
length = number of characters

Example

mystring = InputBox(Enter a string)
mystring = Mid(mystring, 2, 3)
MsgBox The second, third, and fourth characters of your input are  + mystring

e.g. where the input mystring is Hello, the output mystring will be ell

This part of the code is easy to develop in C++ using basic char. However mid function can also be used in the following way;

Usage

Mid(mystring, start, length)

mystring = the string to take characters from start = character to start at (1 is the first character)
length = number of characters

Example

mystring = InputBox(Enter a string)
Mid(mystring, 2, 3) = "abcd"
MsgBox Your string with abc as the second, third, and fourth characters of your input are  + mystring

e.g. where the input mystring is Hello, the output mystring will be Habco

I guess this will be done with references but for my case it did not work. For the first part of the code I wrote the following:

inline char* mid(const char* str, int start, int length)
{
    int len=length+1; // +1 is for '\0' character
    int index=0;
    int end=start+length-1; // formula for [start,end] len=end-start+1 => end=len+start-1
    char* extracted=new char[len];
    for(int i=start;i<=end;i++)
    {
        *(extracted+index++)=*(str+i);
    }

    *(extracted+index)='\0';

    return extracted;
}

So this serves the purpose when mid is on the right hand side. How can I write a code that takes mid on the left hand side.

Any help is appreciated.

I tried the following code just to see if something works but no hope so far:

inline char*& midl(char* str, int start, int length)
{
    int len=length+1; // +1 is for '\0' character
    int index=0;
    int end=start+length-1; // formula for [start,end] len=end-start+1 => end=len+start-1

    return str;
}

And tried the code with the following piece of code

char* str="Lets try";

    midl(str,1,3)="235";

    cout<<"After being processed:"<<str<<endl;
0
Comment
Question by:MacroLand
  • 5
  • 5
  • 2
  • +2
14 Comments
 
LVL 11

Expert Comment

by:cup
ID: 24128335
You have to think about what it means on the left hand side.

char* xxx = "abc";

is not the same as

char yyy[] = "abc";

because

xxx = "defghi";

is legal but

yyy = "defghi";

is not.  On the LHS, mid needs to return a yyy: not an xxx.  Also what would

mid (str,1,3) = "abcdefg";
mid(str,1,3) = "x";

mean?  Note that strings are null terminated.

Why not have a look at the STL string template.  It probably provides a lot of what you want.
0
 
LVL 11

Assisted Solution

by:DeepuAbrahamK
DeepuAbrahamK earned 20 total points
ID: 24128498
Not sure I understand your problem but does this help?


char* mid(const char* str, int start, int length)

{

    int len=length+1; // +1 is for '\0' character

    int index=0;

    int end=start+length-1; // formula for [start,end] len=end-start+1 => end=len+start-1

    char* extracted=new char[len];

    for(int i=start;i<=end;i++)

    {

        *(extracted+index++)=*(str+i);

    }
 

    *(extracted+index)='\0';
 

    return extracted;

}
 

char* midl(const char* str,const char* str1,  int start, int length)

{

    int len=length+1; // +1 is for '\0' character

    int index=0;

    int end=start+length-1; // formula for [start,end] len=end-start+1 => end=len+start-1

    char* extracted=new char[len];

	bool replace=false;

    for(int i=0;i<=end;i++)

    {

        if(i==start || replace==true)

		{

			*(extracted+index++)=*(str1+i);

			replace=true;

		}

		else

			*(extracted+index++)=*(str+i);
 

    }
 

    *(extracted+index)='\0';
 

    return extracted;

}

Open in new window

0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24135988
First, the Mid function is available in C++ MFC as CString::Mid, e. g.

CString s = "Hello";
CString sub = s.Mid(2,3);   // sub = "ell"

When using C++ standard you would take the class std::string like

#include <string>
using namespace std;
...

  string s = "Hello";
  string sub = s.substr(2,3);   // sub = "ell"

which has identical functionality but returns a string object.

The problem when using char pointers and char arrays is that you have to provide an allocation for the final string cause you can't put a termination zero char in the middle of an existing char sequence what would spoil the original string given. Hence there are three (more or less bad) solutions when doing it outside of a string class:

(1) You create the return char array on the heap (by new) and the caller has to delete the array after use.

   char* mid(const char* s, int pos, int len)
   {
         len = min(len, strlen(s) - pos);
         char * p = new char[len+1];
         strncpy(p, s+pos, len);
         p[len] = '\0';
         return p;
    }

     // calling
     char *  sub = mid("Hello", 2, 3);
     ...
     delete []sub;

(2) You use a static buffer in the mid function

   char* mid(const char* s, int pos, int len)
   {
         static int s_len = 0;
         static char* s_p = NULL;
         len = min(len, strlen(s) - pos);
         
         if (len > s_len)
         {
               delete [] s_p;
               s_p = new char[len+1];
               s_len = len;
         }
         strncpy(s_p, s+pos, len);
         s_p[len] = '\0';
         return s_p;
    }

(3) You provide a buffer to the mid, where it could copy the return string to.

   char* mid(const char* s, int pos, int len, char * sub, int szsub)
   {
         len = min(len, szsub-1);
         strncpy(sub, s+pos, len);
         sub[len] = '\0';
         return sub;
    }

     // calling
     char     buf[32] = { 0 };
     char *  sub = mid("Hello", 2, 3, buf, sizeof(buf));
     // here both buf and sub were pointing to the same buffer
 

All three solutions were less good than any string class soolution where the destructor of the string class could care for proper deallocation.    









   
0
 
LVL 4

Author Comment

by:MacroLand
ID: 24145023
So should I inferr from the suggestions that there is no way to use the mid function on the left-hand side?

Such as char* str="Hello";

midl(str,0,3)="123";
cout<<"After being processed:"<<str<<endl;

what I expected to get was the str variable to change to "123lo" meaning that I replaced the first three characters. This can be done in VB 6.0 exactly this way. Also the same mid function can be used on the right hand side to return a substring.

0
 
LVL 4

Author Comment

by:MacroLand
ID: 24145237
For example:

char*& midl(char*& str, int start, int length)
{
    static int i //Dont take this into account for now;

    return str; //return a reference to the pointer

}

USAGE:

char* str="Hello";
midl(str,0,1)="1";

changes str to 1. However I want to change it to "1ello". So my question will be can I return a reference to a block of memory in a char sequence. Or how can I recursively call the function each time to replace one character to get "123lo" from the below code:

char* str="Hello";
midl(str,0,3)="123";

I appreciate the suggestions of string class and MFC. However, this kind of became a mind challenge for me :)

0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 55 total points
ID: 24145304
>>>> that there is no way to use the mid function on the left-hand side?
As a char* is a pointer you only can assign another pointer but not change the data the pointer is pointing to.

You only can make the mid function a left-hand by returning an object type by reference. It can be a CString& or std::string& or a reference to your own string class.

std::string& mid(std::string& s, int off, int len)
{
      s = s.substr(off, len);
      return s;
}

But as you were destroying the object passed as argument by doing this, the mid function is not well-defined.


0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24145444
>> midl(str,0,1)="1";

Why do you want to put in this much effort to try to use C++ the same way as VB ? They're two completely different languages, and each has their own way of doing things.

If you feel more comfortable with VB, then why not stick with that ?
If you need/want to use C++, I suggest sticking with the C++ way of doing things. ie. use the replace method of the std::string type :

        http://www.cplusplus.com/reference/string/string/replace/
std::string str = "Hello";

str.replace(0, 1, "1");

Open in new window

0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24146317
>>>> Why do you want to put in this much effort to try to use C++ the same way as VB ?

In FORTRAN there is a basic string type where you could do
   
  str = 'HELLO'
  str[1:1] = 'B'

thus updating the first char (or any substring) of the original string.

It took me some efforts to have the same functionality with a C++ string class so that

   String str = "HELLO";
   str(0, 0) = "B";

works identically (one problem is that the substring and the original string share the same internal char array but that only the original string was zero-terminated) but I mean it was well invested. If I remember right it was also an assignment in the C++ Annotations of Bjarne Stroustrup.



0
 
LVL 4

Author Comment

by:MacroLand
ID: 24149419
>>Why do you want to put in this much effort to try to use C++ the same way as VB ? They're two completely different languages, and each has their own way of doing things.

Well it is a different taste I can say. It is just that I like to play around with low-level capabilities of C++.

>>In FORTRAN..... It took me some efforts to have the same functionality with a C++ string class so that
>>  String str = "HELLO";
>>  str(0, 0) = "B";

So it is not only me :)
0
 
LVL 53

Expert Comment

by:Infinity08
ID: 24150268
>> It is just that I like to play around with low-level capabilities of C++.

Fair enough :)
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 24153881
>> It is just that I like to play around with low-level capabilities of C++.
Yup. But char* isn't C++ but C. There is no chance to make it work with a non-class type and without overloading operator= .
0
 
LVL 4

Author Comment

by:MacroLand
ID: 24154960
char*& midl(char*& str, int start, int length)
{
    return str; //return a reference to the pointer

}

I guess instead of returning this function as (str+i) to a reference to the *(str+i) and recursively call this function there seems to be some light. However as I am returning a reference I can not add str with i.

>>But char* isn't C++ but C
If C++ is a superset of C, than anything in C can be considered as to be in C++ also :)
0
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 55 total points
ID: 24156168
>>>> If C++ is a superset of C, than anything in C can be considered as to be in C++ also :)
But you need the superset functionality to turn a pointer assignment to an assignment between objects.

The char*&  as a left-hand variable only takes a right-hand pointer. So, whatever the midl function does, e. g. returning the given pointer back without or with adding an offset, finally the returned pointer was overwritten by that what comes from right-hand operand. The only way to overcome that in C++ is creating and returning a new class object which could store the arguments passed to midl in members and determines the operator= function and therefore can make changes on the original string passed onto the midl function. The operator= for C only copies a 32bit or 64bit pointer value with a flat copy.
0
 
LVL 4

Author Comment

by:MacroLand
ID: 24159252
Thank you very much itsmeandnobodyelse and infinity08. I guess I got what I need from the precious comments of itsmeandnobodyelse and supplementary from Infinity08. It is always good to learn new things.

0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now