Does C++ treat char pointers as c style strings? - c++

Does C++ treat char pointers as c-style strings?
int main(int argc,char* argv[])
{
if (argv[1] == "-d")
{
}
}
argv[1] contains a char pointer, how is the statement argv[1] == "-d" not causing the compiler to throw an error because "d" is a string whereas argv[1] is a pointer to a char value

because "d" is a string whereas argv[1] is a pointer to a char value
That's where you're kind of wrong friend.
argv[1] is in this case a char* like you said.
"-d" is a const char[3] (-d plus the null terminator), this array can decay to a pointer which means == compiles.
As pointed out in the comments though, this will probably not do what you expect it to do. This will do a pointer comparison and not a comparison of the actual strings. You'll need to use strcmp for that.

Related

Why does the following program - passing c string to function - not produce the desired output?

I have a simple question C++ (or C).
Why does the following program, passing c string to function, not produce the desired output?
#include <cstdio>
#include <cstring>
void fillMeUpSomeMore( char** strOut )
{
strcpy( *strOut, "Hello Tommy" );
}
int main()
{
char str[30];
//char* strNew = new char[30];
fillMeUpSomeMore( (char**) &str ); // I believe this is undefined behavior but why?
//fillMeUpSomeMore( (char**) &strNew ); // this does work
std::printf( "%s\n", str );
//std::printf( "%s\n", strNew ); // prints "Hello Tommy"
//delete[] strNew;
}
All I'm doing is passing the address of the char array str to a function taking pointer to pointer to char (which after the explicit conversion should be just fine).
But then the program prints nothing.
However this will work with the strNew variable that has been dynamically allocated.
I know that I shouldn't be doing this and be using std::string instead. I'm only doing this for study purposes. Thanks.
I'm compiling with g++ & C++17 (-std=c++17).
char ** is a pointer to a pointer to a character. This means, if it is not a null pointer, it should be the address of some place in memory where there is a pointer.
char str[30] defines an array of 30 char. &str is the address of that array. There is no pointer there, just 30 char. Therefore, &str is not a char **.
So (char**) &str is bad. It tells the compiler to treat the address of the array as if it were the address of a pointer. That is not going to work.
If you instead use char *strNew = new char[30];, that says strNew is a pointer, which is initialized with the address of the first char of an array of 30 char. Then, since strNew is a pointer, &strNew is the address of a char *, so it is a char **, and (char **) &strNew is not wrong.
Generally, you should avoid casts and pay attention to compiler warnings. When the compiler tells you there is a problem with types, work to understand the problem and to fix it by changing the types or expressions involved, rather than by using a cast.
Why does the following program, passing c string to function, not produce the desired output?
When you do a cast like (char **), you aren't specifying which of const_cast, static_cast and / or reinterpret_cast you want, but instead whichever are neccessary to get from your expression's type to the target type.
The expression &str has type char (*)[30], so you are doing a reinterpret_cast to an unrelated type.
The expression &strNew has type char **, so you don't need a cast at all.
When you are writing C++ you should never use a C style cast. You should instead use whichever of the C++ casts (static_cast, const_cast, reinterpret_cast) that you intend.

difference between int* and char* in c++

#include <iostream>
using namespace std;
int main() {
int * a[5];
char * b[5];
cout<<a[1]; // this works and prints address being held by second element in the array
cout<<b[1]; // this gives run time error . why ?
return 0;
}
Can anyone please explain to me cout<<b[1] gives run-time error ?
Shouldn't both int and char array behave similar to each other ?
Because IOStreams are designed to treat char* specially.
char* usually points to a C-string, so IOStreams will just assume that they do and dereference them.
Yours don't.
As others have said, iostream formatted output operators consider char* to point to C-style string and attempt to access this string.
What others have not said so far, is that if you are interested in the pointer, you need to cast the pointer in question to void*. For example:
std::cout << static_cast<const void*>(buf[1]);
An output stream such as cout gives special consideration to char * that it does not give to other pointers. For pointers other than char *, it will simply print out the value of the pointer as a hexadecimal address. But for char *, it will try to print out the C-style (i.e. null terminated array of char) string referred to by the char *. Therefore it will try to dereference the char pointer, as #AlexD points in the comment to your post.
C++ (inheriting it from C) treats character pointers specially. When you try to print a[1] of type int* the address is printed. But when you try to print b[1] of type char* the iostream library - following the rest of the language - assumes that the pointer points to the first character of zero-terminated string of characters. Both your output statements are initialised behaviour, but in the case of char* crash is much more likely because the pointer is dereferenced.

Issue with main arguments handling

I can't compare main() arguments with const char* strings.
Simple code for explaining:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
if(argc>1)
{
for (i=1;i<argc;++i)
{
printf("arg[%d] is %s\n",i,argv[i]);
if(argv[i]=="hello")
printf(" arg[%d]==\"hello\"\n",i);
else
printf(" arg[%d]!=\"hello\"\n",i);
}
}
return 0;
}
Simple compile g++ test.cpp. When I try execute it, I see next thing:
>./a.out hello my friend
arg[1] is hello
arg[1]!="hello"
arg[2] is my
arg[2]!="hello"
arg[3] is friend
arg[3]!="hello"
Whats wrong with my code?
Strings can't be compared with ==, use strcmp:
if (strcmp(argv[i], "hello") == 0)
You have to #include <string.h>
Whenever you use argv[i] == "hello", the operator "==" donot take string as its operand so in actual the compiler compares the pointer to argv[i] with the pointer to constant string "Hello" which is always false and hence the result you are getting is correct, to compare string literals use srtcmp function.
int strcmp(const char *s1, const char *s2);
which compares the two strings s1 and s2. It returns an integer less than, equal to, or greater than zero, if s1 is found, respectively, to be less than, to match, or be greater than s2.
In this statement
if(argv[i]=="hello")
you compare pointers because the string literal is implicitly converted to const char * (or char * in C) that points to its first character. As the two pointers have different values the expression is always false. You have to use standard C function strcmp instead. For example
if( std::strcmp( argv[i], "hello" ) == 0 )
To use this function you should include header <cstring>(in C++) or <string.h> (in C).

What's different about this variable assignment?

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;
}

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.