What's different about this variable assignment? - c++

The following code attempts to put the contents of string c into arg[0].
const char **argv = new const char* [paramlist.size() + 2];
argv[0] = c.c_str();
This is another way to do it.
argv[0] = "someprogram"
I am noticing that later in my program, the second way works, but the first way causes an error. What could possibly be different? How could the first way be changed so that it works right?
This is where the problem occurs:
execvp(c.c_str(), (char **)argv);
If I change it to the following, then the problem doesn't occur. Why is that?
execvp(argv[0], (char **)argv);

In both ways you keep const char* pointers in argv[0]. So the only concern is whether pointers are valid and point to zero-terminated string.
"someprogram" pointer is valid and point to zero-terminated string during program execution.
c.c_str() pointer is guaranteed to be valid from the moment it is returned (by std::basic_string::c_str() function) to the moment string c is changed or destroyed. So if you access string c explicitly or implicitly with any non-const function (including its destructor) the pointer you stored into argv[0] will likely become invalid.
ADD:
Obviously to make argv[0] = c.c_str(); variant work correctly you have to just use argv only in the scope of std::string c (where c exist) and don't change c in any way after you make this assignment (argv[0] = c.c_str();).

You can use _strdup:
const char **argv = new const char* [paramlist.size() + 2];
argv[0] = _strdup(c.c_str());
_strdup allocates memory to store the copy of the string. When you are finished with the string, use free() to return the memory.
The _strdup function looks something like this:
char *_strdup (const char *s) {
char *d = (char *)(malloc (strlen (s) + 1));
if (d == NULL) return NULL;
strcpy (d,s);
return d;
}

Related

Convert to std::string and get const char * in one line

I have a number that I need to convert to a const char * (an API I'm using them requires const char * as input to many of its functions). The following works:
int num = 5;
std::string s = std::to_string(5);
const char * p = s.c_str();
as suggested by answers like those in how to convert from int to char*?, but it involves creating the seemingly unnecessary variable s, so I tried the following, but it doesn't work (p points to an empty string afterwards):
int num = 5;
const char * p = std::to_string(num).c_str();
Is there a clean way I can accomplish this? Why doesn't the second example work? The behavior is very similar to what happens if I made this obvious mistake:
const char * p;
{
std::string tempStr( "hi" );
p = tempStr.c_str( );
// p points to "hi" string.
}
// now p points to "" string.
Which makes me suspect that the issue std::to_string(num) immediately goes out of scope or something similar because it's not used to directly initialize anything.
std::string encapsulates managing dynamic memory (created with new[] and delete[]). Let's break it down.
const char * p = std::to_string(num).c_str();
Create a std::string (with a human-readable representation of num).
Get the new[]ly allocated const char* to the string.
Assign that value to p.
Destroy the std::string → delete[] the allocated const char*.
p points to... deallocated data
If you are using a pointer, the data that the pointer points to must exist throughout the lifetime of that pointer.
So, no, there is no way around this other than new[]ing a copy of the string, which you will have to explicitly delete[] later. And at that point, you've thrown the baby out with the bath and have no need to use std::string.
Create a string that lives at least as long as you want to refer to its internal data.
Just use std::string it does everything you want and everything that you would have to do manually if you don't use it.
When you need to pass a const char* to a const char* function simply use std::string::c_str() like this:
some_api_function(mystring.c_str()); // passes a const char*
What you need is a function which returns a char* which holds your value and can be used to manage its lifetime. The problematic version is broken because the char* points to memory which it does not manage.
For example:
std::unique_ptr<char[]> str(int32_t x)
{
std::unique_ptr<char[]> res(new char[12]);
snprintf(res.get(), 12, "%d", x);
return res;
}
Usestd::string everywhere and don't use const char* when not nessecary. They are basically the same thing. I use const char* only when I'm using a file-path.
Use std::string everywhere and your program should work.

Passing non-const char array to function as const char array is possible?

I was working with the strcmp function in C, then i saw the function as arguments gets:
strcmp(_const char *s1, const char *s2)_;
And actually i passed normal char array and it worked. Any ideas why this happening?
If you have for example the following code
char c = 'A';
char *p = &c;
const char *cp = &c;
then it means that you can change variable c using pointer p but you may not change it using pointer cp
For example
*p = 'B'; // valid assignment
*cp = 'B'; // compilation error
Thus function declaration
int strcmp(const char *s1, const char *s2);
means that inside the function the strings pointed to by s1 and s2 will not be changed.
There are two ways to use const key word to a pointer:
int my_int = 3;
const int* pt = &my_int; //prevent to modify the value that pointer pt points to
int* const ps = &my_int; //prevent to modify the value of pointer ps:
//it means the pointer is a const pointer, you can't modify the value of the pointer
//The value of the pointer ps is a memory address, so you can't change the memory address
//It means you can't reallocate the pointer(point the pointer to another variable)
int new_int = 5;
*pt = &new_int; //valid
*pt = 10; //invalid
*ps = &new_int; //invalid
*ps = 10; //valid
In strcmp function, the two arguments are pointer points to a const value, it means when you pass two char arrays or char pointers to the strcmp function, the function can use the value of those two pointers point to, but the function can't modify the value that you pass to it. That's why it works.
The const reference works in a similar way.
This worked, because passing non-const in place of const is allowed. It is the other way around that is prohibited:
char *hello = new char[20];
char *world= new char[20];
strcpy(hello, "hello");
strcpy(world, "world");
if (!strcmp(hello, world)) {
...
}
The const in the declaration is meant to tell the users of the API that the function will not modify the content of the string. In C++ this is important, because string literals are const. Without the const in the API, this call would have been prohibited:
if (!strcmp(someString, "expected")) { // <<== This would not compile without const
...
}
I think you intend to ask the mechanism of how the variable can compare the array.
if that's the case,
The pointer that has been declared in your example stores the initial address of the array's first element and
the ending point of the string can be determined by the detection null character that which in turn is the ending address of the array.
With that said the strcmp when called the pointer points to the strings or the character passed that is, the command would be assumed as follows strcmp("string1","string2");
and thus the comparison takes place as usual.
hmm i guess by this and with other examples posted around you can get a better picture for your answer.

c++ strange behavior returning char array from char * function

how can i use the windows api without working with char and char * arrays. I want to work only with strings.
second question
char * nextdir(char * cstr) {
string mystring(cstr);
mystring.erase(mystring.find("*.*\\"),4);
mystring.append("\\*.*");
char nextdiir[MAX_PATH]="0";
strncpy( nextdiir, mystring.c_str(), sizeof( mystring ) );
cout<<"NEXTDIIR function="<<nextdiir<<endl;
return nextdiir; //}
the next dir is an array! how can i return it from function?
what happen if i cast it to char * array?
My problem is that other function that uses the nextdir returned value is working strange!
void recursive(char * searchdir){
cout<<"searchdir="<<searchdir<<endl;}
when im doing
recursive(nextdiir(foo)); //now the data printed is not the same but garbage! not like the data printed in call to nextdiir function!!
so i get for example
NEXTDIIR function=c:\windows\*.*
searchdir=garbage
//garbage is unknown characters!
how to fix it?
another questions!!
1)is it because i casted char array name to char * ?
2)how to use windows api without this char and char * mess . only work with strings?
3)what is the difference between char array and char *? the char array name is also constant pointer to the first element then what is the difference???
4)how to return char array from function in c ? in c++?
5)what is the differnce between char * and const char * ? they both the same cuz the value being pointed is unchangeable!
Please help
You are returning a pointer to local variable nextdiir. When the function returns, that variable ceases to exist, leaving you with a dangling pointer. De-referencing it is undefined behaviour.
Why not return an std::string? Then use the std::string::c_str() method to get a const char* pointer to its underlying data.
std::string nextdir(const char * cstr) {
string mystring(cstr);
// do your stuff
return mystring;
}
lots of questions...
how can i use the windows api without working with char and char * arrays. I want to work only with strings.
that will be hard, Win Api requires for some functions a pointer to char* array, you might use here std::vector<char> vec(REQUIRED_SIZE); pass &vec[0] to your api function, and assign &vec[0] to your std::string to get results into std::string.
Second question
char nextdiir[MAX_PATH]="0";
is local to your function, so you are not allowd to return its pointer (it will be UB). You can as above first create std::vector<char> and modify it as you want, and return result as a std::string(&vec[0]).
another questions!!
1)is it because i casted char array name to char * ?
not sure where is that cast, but you had a UB as stated above.
2)how to use windows api without this char and char * mess .
MFC CString allows you to access internal buffer using GetBuffer(0) or GetBufferSetLength(100). std::string does not allow you to safely modify internal buffer, thats why its best to use std::vector. Actually std::vector<TCHAR> would be better, in case you use UNICODE builds where TCHAR will be wchar_t.
3)what is the difference between char array and char *?
both points to array of char type, so no much difference.
the char array name is also constant pointer to the first element then what is the difference???
if it is const char* nm = "alabama"; then it says you cannot modify nm array content
4)how to return char array from function in c ? in c++?
to safely return a char array, you should make sure its lifetime is longer that your function lifetime. This means either you have to allocate memory inside function,- or pass already allocated memory to your function.
5)what is the differnce between char * and const char * ? they both the same cuz the value being pointed is unchangeable!
char* is an array of type char that you can modify in your code, const char* is an array of char type you can only read.

C++ Swap string

I am trying to create a non-recursive method to swap a c-style string. It throws an exception in the Swap method. Could not figure out the problem.
void Swap(char *a, char* b)
{
char temp;
temp = *a;
*a = *b;
*b = temp;
}
void Reverse_String(char * str, int length)
{
for(int i=0 ; i <= length/2; i++) //do till the middle
{
Swap(str+i, str+length - i);
}
}
EDIT: I know there are fancier ways to do this. But since I'm learning, would like to know the problem with the code.
It throws an exception in the Swap method. Could not figure out the problem.
No it doesn't. Creating a temporary character and assigning characters can not possibly throw an exception. You might have an access violation, though, if your pointers don't point to blocks of memory you own.
The Reverse_String() function looks OK, assuming str points to at least length bytes of writable memory. There's not enough context in your question to extrapolate past that. I suspect you are passing invalid parameters. You'll need to show how you call Reverse_String() for us to determine if the call is valid or not.
If you are writing something like this:
char * str = "Foo";
Reverse_String(str, 3);
printf("Reversed: '%s'.\n", str);
Then you will definitely get an access violation, because str points to read-only memory. Try the following syntax instead:
char str[] = "Foo";
Reverse_String(str, 3);
printf("Reversed: '%s'.\n", str);
This will actually make a copy of the "Foo" string into a local buffer you can overwrite.
This answer refers to the comment by #user963018 made under #André Caron's answer (it's too long to be a comment).
char *str = "Foo";
The above declares a pointer to the first element of an array of char. The array is 4 characters long, 3 for F, o & o and 1 for a terminating NULL character. The array itself is stored in memory marked as read-only; which is why you were getting the access violation. In fact, in C++, your declaration is deprecated (it is allowed for backward compatibility to C) and your compiler should be warning you as such. If it isn't, try turning up the warning level. You should be using the following declaration:
const char *str = "Foo";
Now, the declaration indicates that str should not be used to modify whatever it is pointing to, and the compiler will complain if you attempt to do so.
char str[] = "Foo";
This declaration states that str is a array of 4 characters (including the NULL character). The difference here is that str is of type char[N] (where N == 4), not char *. However, str can decay to a pointer type if the context demands it, so you can pass it to the Swap function which expects a char *. Also, the memory containing Foo is no longer marked read-only, so you can modify it.
std::string str( "Foo" );
This declares an object of type std::string that contains the string "Foo". The memory that contains the string is dynamically allocated by the string object as required (some implementations may contain a small private buffer for small string optimization, but forget that for now). If you have string whose size may vary, or whose size you do not know at compile time, it is best to use std::string.

Why is main() argument argv of type char*[] rather than const char*[]?

When I wrote the following code and executed it, the compiler said
deprecated conversion from string constant to char*
int main()
{
char *p;
p=new char[5];
p="how are you";
cout<< p;
return 0;
}
It means that I should have written const char *.
But when we pass arguments into main using char* argv[] we don't write const char* argv[].
Why?
Because ... argv[] isn't const. And it certainly isn't a (static) string literal since it's being created at runtime.
You're declaring a char * pointer then assigning a string literal to it, which is by definition constant; the actual data is in read-only memory.
int main(int argc, char **argv) {
// Yes, I know I'm not checking anything - just a demo
argv[1][0] = 'f';
std::cout << argv[1] << std::endl;
}
Input:
g++ -o test test.cc
./test hoo
Output:
foo
This is not a comment on why you'd want to change argv, but it certainly is possible.
Historical reasons. Changing the signature of main() would break too much existing code. And it is possible that some implementations allow you to change the parameters to main from your code. However code like this:
char * p = "helllo";
* p = 'x';
is always illegal, because you are not allowed to mess with string literals like that, so the pointer should be to a const char.
why is it required for char* to be constant while assigning it to a string
Because such literal strings (like "hi", "hello what's going on", etc), are stored in the read-only segment of your exe. As such, the pointers that point to them need to point to constant characters (eg, can't change them).
You are assigning a string constant (const char*) to a pointer to a non-constant string (char *p). This would allow you to modify the string constant, e.g. by doing p[0] = 'n'.
Anyway, why don't you use std::string instead ? (you seem to be using C++).
If you look at execution functions like execve, you will see that they actually don't accept const char* as parameters, but do indeed require char*, therefore you can't use a string constant to invoke main.