0

I'm new to C, and I'm trying to make a string of variable length, like this:

int main(int argc, char *argv[]) {
    if (argc > 1) {
        char filename[] = argv[1];
    }
    else {
        char filename[] = "temp.txt";
    }
    printf("%s", filename);
}

Of course, that doesn't work because the scope of the string is only within the conditional statement.

How can I assign this variable to a string of an unknown length based on conditional statements?

Cypress Frankenfeld
  • 2,317
  • 2
  • 28
  • 40

5 Answers5

4

This is one way:

char* filename = "this is a different one";

if (boolean)
    filename = "this is a file name";

printf("%s", filename);
Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
  • 1
    Even better: `char *str = condition? "one string": "another";` – Fred Foo Sep 27 '12 at 15:58
  • 1
    Thanks! Could you explain why initializing it as a char pointer works, but initializing it as an array of chars doesn't? – Cypress Frankenfeld Sep 27 '12 at 15:59
  • @larsmans yep, you can do that too if you want maximum shortness. – Seth Carnegie Sep 27 '12 at 15:59
  • @CypressFrankenfeld: `char[] str = "whatever";` is a bit of C magic: it doesn't just assign, but also allocates just enough space to hold `"whatever"` (9 bytes). – Fred Foo Sep 27 '12 at 16:00
  • 1
    @CypressFrankenfeld you just need `filename` to be in the same scope as the `printf` for it to work. Also, you cannot assign to arrays but you can initialise them; `char filename[] = "asdf";` works b/c you are initialising the array with elements, but not `char filename[] = argv[1]` because you are trying to assign a pointer to an array which doesn't work. The way I wrote it works because arrays decay to pointers to their first element, which you can store and use later. – Seth Carnegie Sep 27 '12 at 16:01
  • The main point there is that arrays are not assignable but pointers are. – Seth Carnegie Sep 27 '12 at 16:03
  • @CypressFrankenfeld yes, because you're just assigning pointers which is always fine (unless the pointer is a `const` pointer, but it isn't so it's good here). – Seth Carnegie Sep 27 '12 at 16:07
  • Okay, is there any advantage to using strcpy / strncpy? – Cypress Frankenfeld Sep 27 '12 at 16:09
  • 1
    @CypressFrankenfeld use `strncpy` if you'll potentially be modifying your `filename` later in your code, i.e. adding more path components using `strcat`. In that case, you _shouldn't_ simply assign a pointer to an element of `argv` – pb2q Sep 27 '12 at 16:10
  • @CypressFrankenfeld in addition to what pb2q said, also you need to use `strncpy` if you want to initialise some of your own dynamically allocated memory with the contents of some other memory (maybe a string literal). You may need to do that when you want to build a string at runtime and return it. In this example, since you only use string literals which don't get deallocated at the end of scope, you could return `filename` from a function and use it. But if you wanted to use something other than string literals, you would need `malloc`, and then you might want to use `strncpy` to fill it. – Seth Carnegie Sep 27 '12 at 16:12
2

In simple cases, as in your example, you can declare a char * at an outer scope:

char *str = "a different file name";
if (boolean)
    str = "this file name";

But anything more complicated and you'll need to keep a buffer. Typically filename/path manipulation is more complicated. You can do the same as above with e.g. argv[1], but instead I'd copy the argument, because I might be changing filename at some point later in my program, and just assigning a new pointer to the argument array, or to a literal string, would cause problems.

char filename[MAX_PATH + 1];

strncpy(filename, "temp.txt", MAX_PATH);
if (argc > 1)
    strncpy(filename, argv[1], MAX_PATH);

// .. later
strncat(filename, "temp.txt", MAX_PATH);

But if you're only setting filename once, the following will also work:

char *filename = "temp.txt";

if (argc > 1)
    filename = argv[1];
pb2q
  • 58,613
  • 19
  • 146
  • 147
  • Can you briefly explain the MAX_PATH part? I'm not quite sure how you're determining the length of the filename array. – Cypress Frankenfeld Sep 27 '12 at 16:12
  • 1
    @CypressFrankenfeld sure, if you're going to use a buffer for this, you might begin by _assuming_ an upper-bound on the number of chars in filenames that you'll use. declaring the string with `MAX_PATH` makes space for strings of a certain size, and is an actual constant for this in windows code. outside windows, it's more complicated, see: [this answer](http://stackoverflow.com/questions/833291/is-there-an-equivalent-to-winapis-max-path-under-linux-unix). you could also alloc a buffer to hold exactly the number of chars in `argv[1]`, but you couldn't append later without allocating more space – pb2q Sep 27 '12 at 16:15
1

You have to declare the filename variable outside of the if statement, otherwise it won't be visible after the if statement. Inside the if statement you have to use strcpy to copy the string into the variable. If you don't have to be able to change the string you can use a char pointer instead of an char array.

phlogratos
  • 13,234
  • 1
  • 32
  • 37
0
char filename[256];

if (boolean) {
    strcpy(filename,"this file name");
}
else {
    strcpy(filename, "a different file name");
}
printf("%s", filename);

Or you can use malloc to allocate memory and copy the string.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • 1
    While correct, this is much too complicated. It requires keeping track of how long the string literals are and allocating the appropriate amount of memory for them. The advice to use `malloc` makes things even worse. – Fred Foo Sep 27 '12 at 15:57
0

Define the string before your conditional statement. Then use a string copy function, such as strcpy, to place the value you want into the string. For example:

char filename[ MAX_PATH ];  
if (boolean) { 
    strcpy( filename, "this file name" ); 
} 
else { 
    strcpy( filename, "a different file name" ); 
} 
printf("%s", filename);
StarPilot
  • 2,246
  • 1
  • 16
  • 18