Understanding pointers used for out-parameters in C/C++ - c++

How do I return a char array from a function?
has the following code in the answers:
void testfunc(char* outStr){
char str[10];
for(int i=0; i < 10; ++i){
outStr[i] = str[i];
}
}
int main(){
char myStr[10];
testfunc(myStr);
// myStr is now filled
}
Since I will be using an Arduino where memory is precious I dont want a "temporary variable" for storing some string and then copying it over. I also don't want the function to return anything. I want to use the idea above and do something like:
void testfunc(char* outStr){
outStr="Hi there.";
}
int main(){
char myStr[10];
testfunc(myStr);
}
However, in this case myStr is empty!
Why doesn't this work? How do I fix it?
(I'm relatively new to C, and do have a basic understanding of pointers)
Thanks.

Why doesn't this work?
void testfunc(char* outStr){
outStr="Hi there.";
}
You have:
testfunc(myStr);
When testfunc is called, outStr is assigned the address of the first element of myStr. But in the testfunc function, you overwrite outStr and it now points to a string literal. You are only modifying ouStr, not myStr.
How do I fix it?
To copy a string, use strcpy function (or its secure sister strncpy):
void testfunc(char* outStr){
strcpy(ouStr, "Hi there.");
}

If you want memory reuse - and this is a dangerous place, has you must take really good care about allocation/deallocation responsibility, you should use pointer to string, ie:
#define STATIC_STRING "Hi there"
void testfunc(char**outStr){
*outStr=STATIC_STRING;
}
int main(){
char*myStr;
testfunc(&myStr);
//From now on, myStr is a string using preallocated memory.
}

Related

storing char pointers inside a vector

On rare occasions my program crashes and i don't know why.
I think it might be related to how i store char pointers inside a vector.
vector<char*> vec;
// here i store text for later
void pushToVector(const char *text) {
char *t = new char[strlen(text)+1];
strcpy(t, text);
vec.push_back(t);
}
// now i want to print the first element and then erase it
void print() {
if (vec.size() < 1) return;
printf("print: %s", vec.front());
char *t = vec.front();
vec.erase(vec.begin(), vec.begin()+1);
delete[] t;
}
will this always work? or am i doing something wrong?
The code seems to be ok, although it is rather risky code. These are the unsafe points I see:
You do not check if the parameter text is really a null-terminated string
Working with pure pointers
No clear ownership of the string object on the heap (I wouldn't expect a print function to delete something)
Unless you are bound to C-style strings I would strongly recommend to use std::string.

Copy string value into address

I have the following class
class MyClass{
char myValue[14] //has a 13 character string in it already
public
void toStr(char* str) const;
}
The instruction is: The member function toStr is query that receives the address of a C-style, null-terminated string and fills that address with the object's value
This function assumes that the caller has allocated enough space to hold a thirteen (13) character string.
So I coded:
void myClass::toStr(char* str) const
{
std::strcpy(str, myValue);
}
However str is receiving the address of myValue and not the string itself. I did quite a bit of searching here and couldn't find anything similiar. I CANNOT use dynamic memory in this exercise.
Here is your class used in a simple example (this is all I wanted you to post, but for some reason you couldn't do it).
#include <cstring>
#include <iostream>
class MyClass
{
char myValue[14];
public:
void toStr(char* str) const;
MyClass() { std::strcpy(myValue, "0123456789012"); }
};
void MyClass::toStr(char* str) const
{ std::strcpy(str, myValue); }
int main()
{
MyClass m;
char testString[100];
m.toStr(testString);
std::cout << testString;
}
This function works as expected. I see testString being assigned the myValue text. I added a constructor to MyClass to ensure it is the same as you described, namely that myValue has a 13 character string before the call to toStr.
Now take that example I posted, and either
1) Change whatever you need to change to duplicate your error -- comments can come later as to why what you did doesn't work, or
2) point out what you missed in your code that you see in the example above, thus fixing your error.
There is no plagiarism here, since I have no idea what your assignment is really supposed to be -- this is purely written given your description. See how easy it is just to provide a simple example?
In your assignment there is written that str can hold only 13 characters while myValue is defined as an array of 14 characters. So you should use std::strncpy instead of std::strcpyFor example
void myClass::toStr(char* str) const
{
std::strncpy(str, myValue, 13);
str[12] = '\0';
}
I think you get the weird result because myValue is not zero-terminated. If you are considering the both strings as some buffers of bytes then you should use function std::memcpy In this case the function will look as
void myClass::toStr(char* str) const
{
std::memcpy(str, myValue, 13);
}
I
Try this! You dont need to bother about myValue array size.
void myClass::toStr(char* pstr) const
{
std::string str(myValue);
pstr = new char[str.size()+1];
strcpy(pstr, str.c_str());
}
We obviously need more information on this. But what I understood, your calling code should be as below:
MyClass a;
char *astr = new char[15]; //Allocate enough space for astr to hold myValue
a.toStr(astr);
cout << astr;
delete astr;
Also, value should be assigned in constructor or any other setter as below:
strcpy(myValue,"Test String");
Edit: As explained in another answer by Vlad, strncpy should be better.
This function assumes that the caller has allocated enough space to
hold a thirteen (13) character string.
This means before calling your function, your string already allocated space (as I have done with new).
Looks like you mis-understood question.

How to convert int to char*?

My problem is that I don't know how to convert int value to char array char* m_value. I tried to use itoa but it doesn't work. itoa(m_val, m_wartosc, 10); Maybe there is some other function to do this ?
Main.cpp
int main(int argc, char *argv[])
{
LargeNumber l1;
LargeNumber l3(172839); //how to convert this int to char*
return 0;
}
LargeNumber.h
class LargeNumber{
public:
LargeNumber()
{
m_array = "0"; //zero for no arg.
}
LargeNumber(int val):m_val(val)
{
itoa(m_val, m_array, 10); //doesn't work
//sprintf(m_array, "%d", m_val);
}
LargeNumber(const LargeNumber& p):m_array(p.m_array)
{ } //copy constructor
~LargeNumber(){
delete []m_array; //for object with new
}
public: //should be private
int m_val;
char* m_array;
};
The simple answer is: don't. For two reasons:
As you can see from all the (wrong) other answers, memory management is tricky and bug-prone.
I can't see how storing your value in base-10, in an ASCII string, could possibly be useful. (Compared to, say, a base-232 representation.)
But if you really must store it this way, you will need to allocate the relevant amount of memory, use snprintf to convert (itoa is a non-standard function), and remember to free the memory at the correct time(s) (you will have to read and understand about the Rule of Three).
I would strongly recommend using a std::string instead of a raw C-style array, because it will at least deal with its own memory management, and you will then be able to populate it with a std::stringstream.
The second argument of itoa() needs to be an array in memory large enough to store the null-terminated string. An example:
int number = 172839;
char buffer[10];
itoa(number,buffer,10);
LargeNumber(int val):m_val(val)
{
std::stringstream stream;
stream << val;
m_array = new char[stream.str().size()];
strcpy(m_array, stream.str().c_str());
}
You have to first allocate the array with
m_array = new char[20]
in constructor before calling iota.
the iota doesnt allocate memory.

C++ passing char array to function

I would rather just use a string, but we aren't supposed to as the teacher hates them and wants us to figure out ways to avoid them. So I looked into using a struct, but we aren't that far in the book and she hates it when I skip ahead. So I was thinking of doing this:
#include <iomanip>
#include <iostream>
#include <stdio.h>
using namespace std;
void myfunc(char& );
int main()
{
char myname[12];
cout<<"enter a name ";
cin>>myname;
cout<<"myname is "<<myname;
cout<<"myname is " << myfunc(myname);
getchar();
getchar();
return 0;
}
void myfunc(char &myname1)
{
myname1 = "Billy"
}
But this doesn't work and I don't know why.
One way is to do it like this:
void myfunc(char *myname1)
{
strcpy(myname1,"Billy");
}
You will also need to change your main to:
myfunc(myname);
cout<<"myname is " << myname;
However you have to be careful not to overflow your initial buffer.
The reason why your original code doesn't work is because you can't assign strings to char pointers. Instead you must copy the string to the char*.
This line of code is wrong:
cout<<"myname is " << myfunc(myname);
myfunc() doesn't return anything, its return type is void.
Try using:
char* myfunc(char *myname1)
{
strcpy(myname1,"Billy");
return myname;
}
Or
myfunc(myname);
cout<<"myname is " << myname;
Arrays devolve into pointers when passed as parameters.
So the simple way that you want is:
char* myfunc(char* myname1)
{
return myname1;
}
If you were going to show off you can pass the array by reference.
But if you can't read ahead you will not be able to use this.
char* myfunc(char (&myname1)[12]) // Note you can only pass arrays of size 12
{ // to this function so it is limited in use.
return myname1;
}
TO make it more useful though you could template it:
template<int SIZE>
char* myfunc(char (&myname1)[SIZE])
{
return myname1;
}
myname1 = "Billy" doesn't copy a string it copies a pointer to the constant local memory containing "Billy"
Take a look at strncpy() or memcpy()
Pass it as a char* instead of a char&. You're passing a reference to a single character instead of a pointer to a character array in this code.
Also use strncpy (google it) to set the value of tr char* once you're in the function.
void myfunc(char& ); is the problem it should take in a char * and not a char reference which is what you did.
and in the function use strcpy(char * destination, char *source);

C++ new & delete and string & functions

Okay the previous question was answered clearly, but i found out another problem.
What if I do:
char *test(int ran){
char *ret = new char[ran];
// process...
return ret;
}
And then run it:
for(int i = 0; i < 100000000; i++){
string str = test(rand()%10000000+10000000);
// process...
// no need to delete str anymore? string destructor does it for me here?
}
So after converting the char* to string, I don't have to worry about the deleting anymore?
Edit: As answered, I have to delete[] each new[] call, but on my case its not possible since the pointer got lost, so the question is: how do I convert char to string properly?
Here you are not converting the char* to a [std::]string, but copying the char* to a [std::]string.
As a rule of thumb, for every new there should be a delete.
In this case, you'll need to store a copy of the pointer and delete it when you're done:
char* temp = test(rand()%10000000+10000000);
string str = temp;
delete[] temp;
You seem to be under the impresison that passing a char* into std::string transfers ownership of the allocated memory. In fact it just makes a copy.
The easiest way to solve this is to just use a std::string throughout the entire function and return it directly.
std::string test(int ran){
std::string ret;
ret.resize(ran - 1); // If accessing by individual character, or not if using the entire string at once.
// process... (omit adding the null terminator)
return ret;
}
Yes, yes you do.
If you are using linux/os x, look into something like valgrind which can help you with memory issues
You can change your test function so that it returns a string instead of char *, this way you can delete [] ret in the test function.
OR you could just use a string in test as well and not have to worry about new/delete.
You must call delete for every new otherwise you will leak memory. In the case you have shown you are throwing away the pointer, if you must leave the function as returning a char* then you will need to use two lines to create the std::string so you can retain a copy of the char* to delete.
A better solution would be to rewrite your test() function to return a std::string directly.
You need to do something like this:
for(int i = 0; i < 100000000; i++){
int length = rand()%10000000+10000000;
char* tmp = test(length);
string str(tmp);
delete[length] tmp;
}
This deletes the allocated char-array properly.
By the way, you should always zero-terminate a string if you create it this way (i.e. inside the function test), otherwise some functions can easily get "confused" and treat data behind your string as part of it, which in the best case crashes your application, and in the worst case creating a silent buffer overflow leading to undefined behaviour at a later point, which is the ultimate debugging nightmare... ;)