tags:

views:

464

answers:

6

I found two ways of passing command-line arguments into a character array:

int main (int argc, char **argv)
{
  const char *s1 = argv[0];
  char s2[256];
  strcpy(s2, argv[0]);

  printf("s1: %s\ns2: %s\n\n", s1, s2);
}

Compiled with the IBM xlc compiler on an AIX system Returns

[MyPrompt]> ./a.out

s1: ./a.out

s2: ./a.out

Which implementation (s1 or s2) is correct? s1 is nice because argv[0] can be any length. s2 requires that the length of argv[0] < 256 characters.

I do not understand how/why s1 should work. I think the right-hand side of s1 should be required at compile time, but I think it's generated at run-time.

+3  A: 

The reason s1 works is because the type of argv[0] is a pointer. You are simply assigning the address (not the actual value), which is safe. You aren't performing any kind of allocation or cast.

I typically prefer the first option as you should only be reading from the argument variables.

j0rd4n
If that's the case, shouldn't I change the arguments of int main to (const int argc, const char **argv)?
Pete
The only reason why you couldn't is portability: it's possible there are compilers out there that wouldn't accept it.
quark
const is a new addition to the C language, and since main() was defined way back in the ancient childhood of C, it doesn't have const decoration.However, char* is convertible to const char*, so you don't need to worry about the inconsistency.
Kim Gräsman
j0rd4n: That's not quite right. You can always point a pointer-to-const at a pointer-to-non-const. It's the reverse that's not legal.
quark
The signature of main comes to us from the misty depths of time and is not to be messed with.
dmckee
@quark - Whoops, my bad. You're right - removed the word 'constant' there...
j0rd4n
+2  A: 

If you don't want to change the string then s1 will work.

If you want change the string then you can make a copy of it. You should use the safer strnlen() and strncpy() though if your system supports it.

Karl Voigtland
A: 

If you just want to reference the argument without making any changes to it then s1 is correct.

If you need to modify the argument in any way then you need to make a copy of it like in the s2 example, but in the s2 example you need to explicitly check to see if the length is longer than the buffer you are copying it to. For example if you are taking an argument like filename.jpg as input and saving out filename.gif as the output then you need to make a copy of that argument since you will be changing the extension from .jpg to .gif

KPexEA
+1  A: 

I think the right-hand side of s1 should be required at compile time, but I think it's generated at run-time.

No, it's required every time the statement is encountered. For example:

void f() {
   int x = 1;
   ...
}

The integer x will be initialised to 1 every time the function is called, not at compile time.

anon
+1  A: 

s2 has the delightful property of being susceptible to a buffer overrun.

I have seen people change the value of argv[0]. In some cases, (on some OSes) changing argv[0] will make the program show up in ps as whatever you changed it to.

A: 

I would go with s1, especially for argv[n] where n > 0. Things like s2 open you up for classic buffer overflow attacks. Basically, a user can format an argument that's over 256 characters in length and overwrite information on the stack so they can run any code they want.

Dan Hook