Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2220
  • Last Modified:

pass char* as reference to poulate it in the remote function?

Hi,

how can i pass a char* abc as a function parameter.
In function I want to change the value of abc.

e.g
function
change(abc)
{
 change the value of abc to "changes";
}

in main
{
 char* abc = "in main";
 call change(abc);
 read abc;
}

Now when we read abc, it should read "changed".

Please explain with code as to how to pass, accept and manipulate the string inside main, funciton and protoype.

Thanks
0
dkamdar
Asked:
dkamdar
  • 16
  • 12
  • 3
  • +3
3 Solutions
 
pb_indiaCommented:

char* change(char* abc)
{

return  strcpy(abc,"New Changed Value");

}

int main(void)
{
 char* abc = "in main";   //Old value of abc
 strcpy(abc, change(abc));  //copy "New Changed Value" in abc
 printf("abc value = %s\n", abc);  //this will print "abc value = New Changed Value
return 0;
}

0
 
dkamdarAuthor Commented:
I do not want to return the string.
As i need to return another value which is of the long type.

That is why i asked how to pass it by reference? So that I can cahnge it in remote function
0
 
efnCommented:
You can declare the function parameter char *.

void change(char * abc)
{
 strcpy(abc, "changes");
}

Declare abc to be an array, not a pointer, so you have some space you can write in.  If you declare it as a pointer and initialize it with a constant literal string, you can't (or at least shouldn't) write where the pointer points.  You can pass the name of the array as the pointer parameter.  The array reference will be converted automatically to a pointer to the array's first element.  You can initialize the array with a constant literal string.  This copies the literal string into the array.

in main
{
 char abc[500] = "in main";
 change(abc);
 read abc;
}

The only problem with this is that you have to guess how big to make the array.  If your guess is too big, you waste memory, and if it's too small, you either don't have room for everything you want to store there or you write beyond its bounds and get nasty bugs.  You could avoid all this anguish by using an object of a string class such as the one in the standard library, instead of an old-fashioned C-style character array.

--efn
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
AxterCommented:
You should either pass a pointer to the pointer, or a reference to the pointer
0
 
AxterCommented:

Example of passing a reference to the pointer:

int change(char * &abc)
{
      abc = new char[32];
      strcpy(abc,"New Changed Value");
      return strlen(abc);
}

int main(int , char*)
{
      char* abc = "in main";   //Old value of abc
      change(abc);
      cout << abc << endl;
      return 0;
}
0
 
AxterCommented:
Example passing pointer to a pointer.

int change(char ** abc)
{
      (*abc) = new char[32];
      strcpy(*abc,"New Changed Value");
      return strlen(*abc);
}

int main(int , char*)
{
      char* abc = "in main";   //Old value of abc
      change(&abc);
      cout << abc << endl;

      delete[] abc; //Don't forget to clean up
      return 0;
}
0
 
rstaveleyCommented:
Certainly you *can* use references to pointers.

e.g.
--------8<--------
#include <cstdio>
using std::printf;

void point_to_bye(const char *& cptr) // Ugh
{
      cptr = "Good bye\n";
}

int main()
{
      const char *cptr = "Hello\n";
      printf("%s",cptr);
      point_to_bye(cptr); // Unexpectedly this changes cptr
      printf("%s",cptr);
}
--------8<--------

Note that cptr is a pointer to a const character array in this example, but it isn't a const pointer (i.e. you can use the reference to make it point to another const character array). If another coder failed to read the point_to_bye implementation, she'd easily be tripped up by this function. It doesn't do what you expect it to do. In my experience, most coders incorrectly read const char *cptr as "this isn't going to change"; you seldom see const char * const cptr, which really is a const pointer to const.

Certainly this works, but it is much more conventional to have a function return a pointer. That way you can see the pointer being assigned a new address with operator=.

i.e.
--------8<--------
#include <cstdio>
using std::printf;

const char* get_pointer_to_bye()
{
      return "Good bye\n";
}

int main()
{
      const char *cptr = "Hello\n";
      printf("%s",cptr);
      cptr = get_pointer_to_bye(); // No surprise that cptr is changed
      printf("%s",cptr);
}
--------8<--------

Going the conventional route is much more readable. You can guess that cptr is being changed, without reading the get_pointer_to_bye implementation.
0
 
AxterCommented:
>>I do not want to return the string.
>>As i need to return another value which is of the long type.

If you need a return value, you can use an argument to retrieve.  This will allow you to use the return value for the string pointer.

char* change(int& len)
{
     abc = new char[32];
     strcpy(abc,"New Changed Value");
     len = strlen(abc);
     return abc;
}

int main(int , char*)
{
     char* abc = "in main";   //Old value of abc
     int x;
     abc = change(x);
     cout << abc << endl;
     cout << x << endl;

     delete[] abc; //Don't forget to clean up
     return 0;
}
0
 
rstaveleyCommented:
...or return a user-defined struct or std::pair<std::string,int>

e.g.
--------8<--------
#include <iostream>
#include <string>
#include <utility>   // Used for std::pair<>

typedef std::pair<std::string,int> MyPair;

MyPair f()
{
      return MyPair("Good-bye",1234);
}

struct MyStruct {
      std::string string;
      int integer;
      MyStruct(const std::string& string,int integer) : string(string),integer(integer) {}
};

MyStruct f2()
{
      return MyStruct("Fare well",9876);
}

int main()
{
      std::string str = "Hello";
      std::cout << str << '\n';

      MyPair mypair = f();
      str = mypair.first;
      std::cout << str << ' ' << mypair.second << '\n';

      MyStruct mystruct = f2();
      str = mystruct.string;
      std::cout << str << ' ' << mystruct.integer << '\n';      
}
--------8<--------

With return value optimisation, you'll find that this approach isn't as inefficient as your gut instinct might suggest.
0
 
AxterCommented:
>>...or return a user-defined struct or std::pair<std::string,int>
That would work, but it's less efficient.
It's much more efficient, to have the function take a reference to an argument, then to return an object by value.
0
 
itsmeandnobodyelseCommented:
You should consider using a string class rather than char*.

  #include <string>
  using namespace std;

  void changeString(string& abc)
  {
       abc = "xyz and abc and whatever";
  }

  int main()
  {
        string abc = "abc";
        changeString(abc);

        return 0;
  }

You see, it's much easier and you could take any string class you want, or even write one yourself:

class String
{
      char* m_buf;
      int     m_alloc;
      int     m_len;
public:
      String() : m_buf(NULL), m_alloc(0), m_len(0) {}
      String(const char* buf)
           { createString(buf, strlen(buf)); }
      String(const String& str)
           { createString(str.m_buf, str.m_len); }
      ~String() { delete [] m_buf; }
      operator const char* () const { return m_buf; }
      String& operator = (const char* buf)
      { if (buf != m_buf) { delete [] m_buf; createString(buf, strlen(buf)); } return *this; }
      char operator[] (int i)
      { if (i >= 0 && i < m_len) return m_buf[i]; return '\0'; }
      int length() const { return m_len; }
      bool operator == (const char* buf) const
      { return strcmp(m_buf, buf) == 0; }

protected:
     void createString(const char* buf, int len)      
     { m_len = len; m_alloc = len+1; m_buf = new char[m_alloc]; strncpy(m_buf, buf, m_alloc);}
};

Regards, Alex
0
 
rstaveleyCommented:
I was curious about the extent to which the efficiency argument is true.

I tried profiling the following with gprof (GNU's profiler):
--------8<--------
#include <iostream>
#include <string>

struct MyStruct {
     std::string string;
     int integer;
     MyStruct() {}
     MyStruct(const std::string& string,int integer) : string(string),integer(integer) {}
};

MyStruct f2()
{
     return MyStruct("x",1234);
}

void test2()
{
      MyStruct mystruct;
      for (int i = 0;i < 10000000;i++) {
            mystruct = f2();
      }
}

void f1(std::string string,int& integer)
{
      string = "x";
      integer = 1234;
}

void test1()
{
      std::string string;
      int integer;
      for (int i = 0;i < 10000000;i++) {
            f1(string,integer);
      }
}

int main()
{
      test1();
      test2();
}
--------8<--------

i.e. test1 runs a whole lot of tests with a function passing references and test2 runs a whole lot of tests returning a structure by value, which we expect to get return value optimisation, when optimisation is enabled.

Compilation with maximum optimisation was:

   g++ -O3 prof1.cpp -g -pg

i.e. -O3 for maximum optimisation and the necessary switches to enable gprof output.

Looking at the output from gprof on a FreeBSD box, it appears to be the case that test2 is more efficient than test1, when we optimise.
--------8<--------
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
  7.9      12.32     1.05        1  1045.90  2944.34  test1__Fv [5]
  5.0      12.99     0.66        1   663.09  4409.18  test2__Fv [2]
--------8<--------

I tried the same with optimisation disabled.

i.e.
        g++ -O0 prof1.cpp -g -pg

Looking at the output from gprof on the same FreeBSD box, it appears to be the case that test1 is more efficient than test2 (as Axter predicted), when optimisation is disabled.
--------8<--------
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
  0.3     115.55     0.40        1   400.39 13078.46  test2__Fv [3]
  0.2     118.94     0.20        1   200.20  9565.09  test1__Fv [7]
--------8<--------

Conclusion: Don't bother optimising until you've profiled.
0
 
rstaveleyCommented:
Oh that wasn't very fair, I've just noticed:

> void f1(std::string string,int& integer)

Failed to pass the string as a reference (doh!)... let me try that again.
0
 
AxterCommented:
>>Conclusion: Don't bother optimising until you've profiled.

However, make sure that your profile is correct.

Your test is invalid, since you're not passing by reference, and instead you're passing by value in both test.

Conclusion: Don't ever rely on you're own profile results, without validation by a second eye.
It's very very easy to incorrectly peform a profile test.
This is espcially so, when you're trying to prove a case.

void f1(std::string string,int& integer) //string is passing by value

FYI:  You should never name a variable the same name as any object in the C++ standards.
0
 
rstaveleyCommented:
OK, passing the string as a reference gets similar results.

Unoptimised:
g++ -O0 prof1.cpp -g -pg
--------8<--------
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
  0.4      95.15     0.35        1   350.59 12341.42  test2__Fv [3]
  0.2      98.68     0.21        1   205.08  7087.29  test1__Fv [7]
--------8<--------

Optimised:
g++ -O3 prof1.cpp -g -pg
--------8<--------
  4.8      11.81     0.60        1   595.70  2269.53  test1__Fv [5]
  4.0      12.30     0.50        1   499.02  3859.37  test2__Fv [2]
--------8<--------

Return value optimisation makes the returned structure approach faster than reference passing, when you enable optimisation. [Unless I've completely misunderstood gprof!]
0
 
rstaveleyCommented:
> Conclusion: Don't ever rely on you're own profile results, without validation by a second eye. It's very very easy to incorrectly peform a profile test. This is espcially so, when you're trying to prove a case.

Yes, I know that only too well alas. Would you be happy to run a similar test with your profiler, Axter? My second test changed...

     void f1(std::string string,int& integer)

...to...

     void f1(std::string& string,int& integer)

But came to the same [hasty] conclusion.

> FYI:  You should never name a variable the same name as any object in the C++ standards.

string isn't in the global namespace.
0
 
AxterCommented:
I still see problems with the code.

Since you're not doing anything with the data, the compiler can optimize away some of the test code, which would make your test invalid.

Proper test would insure this couldn't happen.
Also, don't like the idea that the variables are using the same name as a C++ object.

Also test2 is not performmnig the same function as test1.
In test1 you're handing in values.  test2 doesn't have any logic input.

The following would be a more accurate profile comparison:

#include <iostream>
#include <string>

struct MyStruct {
     std::string m_strdata;
     int m_integer;
     MyStruct() {}
     MyStruct(const std::string& strdata,int integer) : m_strdata(strdata),m_integer(integer) {}
};

MyStruct f2(int value)
{
     return MyStruct("x",++value);
}

void test2()
{
     MyStruct mystruct;
     for (int i = 0;i < 10000000;i++) {
          mystruct = f2(mystruct.m_integer);
     }
       std::cout << mystruct.m_integer << std::endl;
}

void f1(std::string &strdata,int& integer)
{
     strdata = "x";
     ++integer;
}

void test1()
{
     std::string strdata;
     int integer = 0;
     for (int i = 0;i < 10000000;i++) {
          f1(strdata,integer);
     }
       std::cout << integer << std::endl;
}

int main()
{
     test1();
     test2();
}
0
 
AxterCommented:
>>Would you be happy to run a similar test with your profiler, Axter? My second test changed...

Here's the code:
#include <windows.h>

#include <iostream>
#include <string>

struct MyStruct {
      std::string m_strdata;
      int m_integer;
      MyStruct() {}
      MyStruct(const std::string& strdata,int integer) : m_strdata(strdata),m_integer(integer) {}
};

MyStruct f2(int value)
{
      return MyStruct("x",++value);
}

int test2()
{
      MyStruct mystruct;
      mystruct.m_integer = 0;
      for (int i = 0;i < 10000000;i++) {
            mystruct = f2(mystruct.m_integer);
      }
      return mystruct.m_integer;
}

void f1(std::string &strdata,int& integer)
{
      strdata = "x";
      ++integer;
}

int test1()
{
      std::string strdata;
      int integer = 0;
      for (int i = 0;i < 10000000;i++) {
            f1(strdata,integer);
      }
      
      return integer;
}

int main(int, char*)
{
      DWORD Start, Time1, Time2;
      Start = GetTickCount();
      int t1 = test1();
      Time1 = GetTickCount() - Start;
      Start = GetTickCount();
      int t2 = test2();
      Time2 = GetTickCount() - Start;

      std::cout << t1 << std::endl;
      std::cout << t2 << std::endl;

      std::cout << Time1 << std::endl;
      std::cout << Time2 << std::endl;

      return 0;
}
0
 
AxterCommented:
The above code yield the following results:

10000000
10000000
1422
7375


Big, big difference.  Passing by reference is faster by a factor of 5.
0
 
AxterCommented:
I even tried to give your code an edge by not even include input values:

MyStruct f2()
{
      return MyStruct("x",99);
}

int test2()
{
      MyStruct mystruct;
      mystruct.m_integer = 0;
      for (int i = 0;i < 10000000;i++) {
            mystruct = f2();
      }
      return mystruct.m_integer;
}

And I kept the reference code the same.  This should have given the pass by value some added speed.  But the results were nearly the same.

The only way pass by value would be faster, is if the compiler complete optimize away the code.  In other words, nothing is being performed.

By adding code that uses the logic performed in the test, you reduce the ability for the compiler to optimize away the code.
This is something you should always do when testing code for performance comparison.

If you leave out code that forces the compiler to include the code logic, then there is no way to know for certain what you’re testing.
0
 
AxterCommented:
I forgot to mention.
The above test was peformed using VC++ 6.0 compiler on Windows 2000 OS.
The results are that of the code which was compiled in *Release* mode.

The debug version shows the pass by value to be even worse.
I never [intensionally :-)], use debug version to test code, so above line if just an FYI:
0
 
rstaveleyCommented:
You're right, Axter.

You've seen it with Windows, but it also weighs in favour of passing by reference on GNU+FreeBSD, with the alteration:
--------8<--------
//#include <windows.h>
#include <ctime>
typedef long DWORD;
DWORD GetTickCount()
{
        return clock();
}
--------8<--------

...here's the output on my box:
--------8<--------
rstaveley@box:~/src$ g++ prof2.cpp
rstaveley@box:~/src$ ./a.out
10000000
10000000
829
1661
rstaveley@box:~/src$ g++ -O3 prof2.cpp
rstaveley@box:~/src$ ./a.out
10000000
10000000
274
520
--------8<--------

It's good to have these things aired. That is to say, it's good for me. Thanks for the correction.
0
 
itsmeandnobodyelseCommented:
>> std::string& string

My first 2000 points i got by convincing someone not using the same name for arguments of member functions as for member variables... but that is worse ;-)  

>> Big, big difference

Yes, but 7 seconds for 10,000,000 calls isn't bad. So, for most programs it is  "un quantité negligable".

I prefer passing by (const) reference because it's much easier to debug ...


Regards, Alex


0
 
AxterCommented:
>>Yes, but 7 seconds for 10,000,000 calls isn't bad. So, for most programs it is  "un quantité negligable".

If you're a user waiting for calculated results, I think waiting 7 seconds is a big deal compare to waiting 1.4 seconds.

Just think how annoying it would if you had to wait 7 seconds for each web page to display.
0
 
rstaveleyCommented:
> "un quantité negligable"

:-) Very true, I guess what really matters is whether the client finds it easier to handle returned structs or if modifying referenced parameters is more transparent.
0
 
itsmeandnobodyelseCommented:
>> how annoying it would if you had to wait 7 seconds

You have it right, Axter. Factor 5 is a big difference and passing strings by (const) reference is a very simple to use alternative to passing it by value. I wanted to say that there are only a few applications that are handling with 10 millions of strings while the user is waiting...

0
 
AxterCommented:
There are two rules of thumb I follow when it comes to optimization.

1.      Don’t optimize unless you need to
2.      When all things are equal (or nearly equal), use optimize code over less efficient code

These two rules may seem to contradict themselves, but what it basically means is that you shouldn’t try to make real complicated code just for the sake of optimizing when you don’t know that you need the optimization.
On the other hand, you shouldn’t go out of your way to develop less efficient code, unless what you’re getting in return is worth losing efficiency.
Determining this value can be very subjective.

One programmer can see a value of more readable code, while another programmer may see the same code, and determine it to be less readable.

In general, I usually lean towards efficiency over readability, and if I really think readability is a problem, I add comments to the code instead of making the code less efficient.

0
 
rstaveleyCommented:
Missing from this (because it wasn't relevant to the author's now long-forgotten question :-) is...

void f1(std::string* strdata,int* integer)
{
     *strdata = "x";
     ++*integer;
}

This surely has the same efficiency as void f1(std::string& strdata,int& integer), but the calling code has an obvious indication of mutation, because the address-of operator is needed (cf. C's scanf function). IMHO, passing non-const references should have a name which warns you something unconventional is happening.

> I add comments to the code instead of making the code less efficient.

Yes,... but hand on heart, how many times do those comments fail to make it into client code (i.e. where the function is called), rather than just the splendidly-commented header file?

Other than istream's insertion operator (which visually warns you that you are looking at something which is back-to-front) and anything passed as a pointer, I don't immediately expect to see a parameter changed by a function.
0
 
AxterCommented:
>>Other than istream's insertion operator (which visually warns you that you are looking at something which is back-to-front) and anything passed as a >>pointer, I don't immediately expect to see a parameter changed by a function.

I think this really depends on the programmer back ground.
IMHO, most C programmers would agree with you.
But most C++ programmers would assume a function will modify an argument unless constant is used in the argument declaration.

I really don't like using pointer to pointers, becuase IMHO, it makes everything more complicated, and less readable.  This includes the using function as well as the calling function.

f1(&data, &intdata);//IMHO less readable

void f1(std::string* strdata,int* integer)
{
     *strdata = "x"; //IMHO less readable
     ++*integer;//IMHO less readable
}

IMHO, Not only is the above less readable, but also easier to make a mistake.

IMHO, the following is far easier to read and understand, then above code
void f1(std::string& strdata,int& integer)
{
     strdata = "x"; //IMHO readable
     ++integer;//IMHO readable
}

f1(data, intdata); //Easier to read and easier to code

It's also easier to find memory leaks if you reduce the amount of pointers to a minimum.
If you have a lot of cryptic code with pointers everywhere, it makes it much harder to find leaks.

As I stated before, this is subjective which is why I put a bunch of IMHO every where.
But I highly recommend to newbies to always prefer using reference over pointers when possible.
0
 
rstaveleyCommented:
You've focused somewhat on the function implementation rather than the calling code. The calling code is where your reader is likely to be starting his journey of understanding.

With reference to the calling code, I take issue with your comment:

> f1(data, intdata); // Easier to read and easier to code

I'd say that the implications of the function were easier to overlook than...

   f1(&data, &intdata); // Implications of function are highlighted by the need for &

But an appropriate function name would help :-)

I can and do make life easy for myself with references for real life implementations. This is something that I'd omit in an EE post for the sake of brevity.
--------8<--------
void f1(std::string* p_strdata,int* p_integer)
{
     //  Get some references to the parameters - this shouldn't add code to the function
     std::string& strdata = *p_strdata;
     int& integer = *p_integer;

     // Now implement the real code
     strdata = "x";
     ++integer;
}
--------8<--------

> I really don't like using pointer to pointers, becuase IMHO, it makes everything more complicated, and less readable.

I know that I'm vascilating, but I also have that misgiving. That's is what brings me back to my predilection for returned structures or at a pinch tuples like std::pair<>, when multiple return values are needed. In practice, this doesn't really crop up all that much in my world, and  when it has its efficiency hasn't been an issue.

> It's also easier to find memory leaks if you reduce the amount of pointers to a minimum

Certainly, but that's not really relevant in this context.

> But I highly recommend to newbies to always prefer using reference over pointers when possible.

Yes. I'd also recommend that they prefer using function return values and take a step back from their design, if they find themselves needing to return more than one value from a function. Multiple return values are an intermediate/advanced C++ trick. I'd be inclined to advise a newbie that you can only return one value and leave it at that.

I don't think it's only because of the C heritage of C++ that you don't see the standard library implementing functions with non-const reference parameters (other than swap of course... any others??).

Again, thanks for putting me straight about the profiling, Axter. I'll know to look at the assembler listing next time I play around with the profiler with demonstration code.... or perhaps stick to using clock ticks like you do.
0
 
rstaveleyCommented:
> any others??

Oh yes, there's getline of course, as defined in <string>
0
 
AxterCommented:
>>You've focused somewhat on the function implementation rather than the calling code. The calling code is where your reader is likely to be starting his
>>journey of understanding.

No.  I focused on both.  In my comments I stated it's difficult to read both for the calling function, and for the callee.

>>I'd say that the implications of the function were easier to overlook than...

Not so for most real world situation.
In most real world applications, the function name tells you the implications.
Example:
CString data;
file.ReadString(data);

std::string data;
std::getline(file, data);

IMHO, if you really want to focus on the calling code, it's better to give the Function a good name, so as to tell the callee what is going on, then to depend on the argument type.
void ReadString(CString &data); //Tells me more

void functiion1(CString *data);//Tells me very little

IMHO, the focus should be on the function name, and not the argument type.
I see too many developers who create none constant argument types like functiion1, but do not modify the argument.
So (IMHO) the argument type is not a good indicator to use to determine if the variable will be modified.
0
 
rstaveleyCommented:
I can't argue with your examples and with hindsight I can add STL algorithms to your list - e.g. copy. I also agree with you that it is wise to cater for bad common practice like const incorrectness, because not all coders have enough time to check all of the relevant boxes in their RAD tool.

I guess we're both trying to do damage limitation, steering others into practices that are least likely to result in unintelligible code. Present company being beyond jurisdiction :-)

However, I can't see the point in designing a function like...

     void ReadString(CString &data);

...because its a lost opportunity to use a return value. If data isn't being used as an input, why pass the existing value to the function?

A ReadString function which returns CString is much better.

     CString ReadString();

I can see the point in std::getline for std::string, because the stream state and the string are returned like istream::operator>>.

I've not read many "good practices" guidelines on the subject of non-const reference parameters. I notice one at http://www.goingware.com/tips/parameters/ptrparams.html which proposes that you make the in/out implicit in the parameter name, but you wouldn't see that in the calling code, and you may as well impose const correctness in your good coding practices if you need to see the prototype anyhow.
0
 
AxterCommented:
>>A ReadString function which returns CString is much better.
>>     CString ReadString();

This is passing back by value, which again is *usually* less efficient then passing by reference.
However, this paticular example is an exception to the rule.  CString class uses reference counters, which means it would probably be just as efficient to pass in by reference as it would be to pass back by value.

Also, I mistyped the declaration for above function.
It should have been the following:
BOOL ReadString(CString& rString);

So they're already using the return back value for validating the read operation.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 16
  • 12
  • 3
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now