I have some code in which an array of strings is defined in a conditional statement. The array is out of scope where I need it. So I defined another pointer in the outer scope. In the conditional statement I assign the array address to the outer scope pointer. The code compiles without warnings for dangling pointers and such, but the code is not correct.
I produced a (correctly compiling) MRE below. The function does not make any sense. Essential is that:
- The array of strings
cmd_stris defined inside a condition - The number of strings is variable
- The length of the strings is variable
- The strings are either constants or null terminated strings
- The last string only contains
NULL - I use the resulting strings array outside the condition
int noCmd(int *opt) {
int local_opt;
const char** cmd = NULL;
local_opt = *opt; // Make sure the compiler cannot know this value to avoid optimization.
if (local_opt == 1) {
const char* cmd_str[] = {"foo", "bar", NULL};
cmd = cmd_str;
} else {
const char* cmd_str[] = {"flop", "blah", NULL};
cmd = cmd_str;
}
// Dummy statement to force referencing cmd
// actually I need the contents of cmd here
return sizeof(cmd);
}
The main problem is that cmd doesn’t have any value in the return statement. This is confirmed by the assembly listing where cmd does not get a value assigned:
Dump of assembler code for function noCmd:
0x00007ffff7fb9e80 <+0>: mov $0x8,%eax
0x00007ffff7fb9e85 <+5>: ret
End of assembler dump.
My reasoning is that cmd_str goes out of scope. Since it is not a valid pointer anymore, it is not allowed to be used. And the compiler optimizes all code out, because the nothing is used inside the scope and must not be used outside the scope.
The actual code is obviously much more complicated that this MRE. But the problem (conditional char** assignment) and the need for the strings outside the scope is the same.
How do I solve this?
I cannot do a memcpy from cmd_str into cmd, because I don't know the size. I might loop through each string in cmd_str, find the size of the string and then copy each string into cmd one by one, but that is very inelegant.
I cannot declare cmd_str in the outer scope, because
const char* cmd_str[]
is invalid.
Neither can I declare
const char** cmd_str
because it would be impossible to assign a number of strings to cmd_str[].
Isn't there a better way to define an array of strings inside a condition and use it outside the condition? The string to be assigned are either constants or null terminated strings. The last string gets the NULL value.
cmddoesn't have a value in thereturnstatement. The function returns the size of a pointer, regardless of what you've been doing with it.sizeofis a compile-time constant unless you're playing games with VLAs.sizeof cmdis simplysizeof (const char**)and does not odr-usecmd. Poor choice of dummy statement.mallocor to an externally declared emptystructpassed in), is there a reason that wouldn't work?sizeofactually does. It does not return the size of the arraycmd_strpoints to (or might at some point have pointed to). It just returns the size of the variablecmd_strin bytes, but that variable is a pointer and not an array, and the compiler can compute this size without ever dereferencing the pointer.