error: initializer element is not a compile-time constant - c

I have been looking for answers but could not find anything to make this code run. I get av[1] highlighted by the compiler in the main function when declaring:
static char const *str = av[1];
Here is the code I tried to run with gcc:
#include <stdio.h>
#include <stdlib.h>
char *ft_strjoin(char const *s1, char const *s2);
void fct(char **av)
{
static char const *str = av[1];
str = ft_strjoin(av[1], av[1]);
printf("%s\n", str);
}
int main(int ac, char **av)
{
fct(&av[1]);
fct(&av[1]);
fct(&av[1]);
fct(&av[1]);
fct(&av[1]);
fct(&av[1]);
}
I found this interesting but I still don't get it and don't know how to run this code.

Quoting C11, §6.7.9, Initialization
All the expressions in an initializer for an object that has static or thread storage duration
shall be constant expressions or string literals.
In your code,
static char const *str = av[1];
av[1] is not a compile time constant value (i.e., not a constant expression). Hence the error.
You need to remove static from str to avoid the issue.

static variables need to be initialised with a compile time constants (constant literals). av[1] will be calculated at runtime and that's why you are getting the error message.

You could simulate that behaviour by writing:
static const char *str;
static bool already;
if ( !already )
{
str = av[1];
++already;
}
However this would be redundant compared to the solution of:
const char *str;
because you immediately overwrite that value anyway with the return value of your function.
(Also you pass the same argument in every call, so even if you used str, it still doesn't need to be static).

Related

returning string from a function but prints null, what is the reason?

I am trying to return a string from str function but it prints (null)
#include<stdio.h>
char* str()
{
char hi[10] = "return this";
return hi;
}
void main()
{
printf("%s", str());
}
read static variables or global variables to access the variable outside the functions
there is an overflow in your code, read buffer overflow in c
Also read What should main() return in C and C++?
#include<stdio.h>
char* str()
{
static char hi[] = "return this";
return hi;
}
int main()
{
printf("%s", str());
return 0;
}
In GCC at least your code compiles with teh following warnings:
main.c:12:19: warning: initializer-string for array of chars is too long
main.c:13:12: warning: function returns address of local variable [-Wreturn-local-addr]
Which more or less is a direct answer to your question. If you did not get these warnings, consider the compiler switched you are using, for GCC I suggest at least -Wall -Werror - that will output the most useful warnings without being pedantic, and make those warnings errors so will prevent successful compilation until you fix them.
You are returning a pointer to a local-automatic variable that is no longer in scope after the function returns, so the result is undefined. You have also tried to initialise an array with more characters that you have reserved.
What the compiler has done here is given the invalid initialiser, it has set the address of hi to null, and printf has handles the null pointer by printing (null). That is behaviour specific to your compiler and C library - in other cases something different may happen. More insidious that that is that if your initialiser was not invalid (by being shorter), it is likely to have appeared to work and you might never have asked the question, but it would still be incorrect, and in more complex code would likely at some point cause observable erroneous behaviour.
In this particular case you could do any of the following:
const char* str()
{
static const char* hi = "return this";
return hi;
}
const char* str()
{
static const char hi[] = "return this";
return hi;
}
char* str( char* str, int maxlen )
{
str[maxlen] = '\0' ;
return strncpy( str, "return this", maxlen - 1 ) ;
}
void main()
{
char* buffer[32] ;
printf("%s", str(buffer, sizeof(buffer));
}
The most appropriate solution (and the above are by no means exhaustive) depend on what you actually want to do, since each solution differs semantically, and on its own this function is hardly practical. It would need a concrete real-world example to give best advice.
The problem is with the scope of the character array.
The solution for this issue is to make the address of that variable visible to the caller function!
i.e.
one of the easiest solutions is use the below line in the declaration part of hi variable in your str() function.
i.e.
static char hi[10] = "return th";
in the declaration.
This way you wouldn't need to change anything in this program BUT in the whole program, this variable WILL BE visible/accessible throughout the execution.
#include"stdio.h"
char* str() {
static char hi[10] = "return th";
return hi;
}
int main() {
printf("%s", str());
return 0;
}
#include<stdio.h>
#include<stdlib.h>
char* str(){
//malloc is used to allocate memory
char *hi=(char*)malloc(sizeof(char)*20);
char ch[]="return this\0";
for(int i=0;i<sizeof(ch);i++)
hi[i]=ch[i];
return hi;
}
int main(){
printf("%s", str());
return 0;
}
you can find more about malloc and sizeof operator.

C literals, where are these stored

Consider the following code:
#include <stdio.h>
void f(const char * str) {
str = "java";
}
void main (int argc, char * argv[]) {
const char *str = "erlang";
f(str);
printf("%s\n", str);
}
The output is "erlang" and I don't quite know why..
My current knowledge says that string literals "erlang" and "java" are both stored in the process adress space, within section "constants". And according to this, the fucntion f should change the pointer to point to "java", but this doesn't happen. Could someone please explain what is going on here?
Because function arguments are passed by value in C and modifying arguments in callee won't affece caller's local variables.
Use pointers to modify caller's local variables.
#include <stdio.h>
void f(const char ** str) { /* add * to declare pointer */
*str = "java"; /* add * to access what is pointed */
}
int main (int argc, char * argv[]) { /* use standard signature */
const char *str = "erlang";
f(&str); /* add & to get a pointer pointing at str */
printf("%s\n", str);
}
C has copy by value. When str is passed as an argument to f, it is copied first, and that very copy is actually passed to f. Assigning "java" to that copy doesn't do anything to the original str in main.
Since you are passing the value that means call by value you will see the output as java if you pass the reference like this:
#include <stdio.h>
void f(const char ** str) {
*str = "java";
}
void main (int argc, char * argv[]) {
const char *str = "erlang";
f(&str);
printf("%s\n", str);
}
output:
rabi#rabi-VirtualBox:~/rabi/c$ gcc ptr1.c
rabi#rabi-VirtualBox:~/rabi/c$ ./a.out
java
Function parameters are its local variables. You can imagine the function definition and its call the following way (I changed the name of the parameter from str to s for clearity)
void f(/*const char * s*/) {
const char *s = str;
s = "java";
}
//...
const char *str = "erlang";
f(str);
Any changes of the local variable s does not influence on the original variable str used as the argument. The variable str itself was unchanged.
You should pass arguments by reference if you are going to change them in a function. For example
#include <stdio.h>
void f( const char ** str )
{
*str = "java";
}
int main( void )
{
const char *str = "erlang";
f( &str );
printf( "%s\n", str );
}
The program output is
java
Take into account that according to the C Standard function main shall have return type int.
Could someone please explain what is going on here?
Many good answers all ready yet thought I'd try to perform a detailed walk-though with OP with slightly modified code.
Consider what happens with f("Hello World"). "Hello World" is a string literal. It initializes a char array. When an array is passed to a function or assigned to a pointer, it is converted to the address of the first element of the array. f() receives a copy of the address of 'H' in its str. #1 prints "Hello World". str is re-assigned to the address of 'j'. #2 prints "java". The function ends without affecting "Hello World".
With str = "erlang", str receives the address of the 'e'. #3 prints "erlang". On the function call, the value of main()'s str is copied to the f()'s str. #1 prints "erlang". Like before, str is re-assigned to the address of 'j'. #2 prints "java". The function ends without affecting main()'s str. #4 prints "erlang".
#include <stdio.h>
void f(const char * str) {
printf("f() before str='%s'\n", str); // #1
str = "java";
printf("f() after str='%s'\n", str); // #2
}
int main(void) {
f("Hello World");
puts("");
const char *str = "erlang";
printf("main() before str='%s'\n", str); // #3
f(str);
printf("main() after str='%s'\n", str); // #4
return 0;
}
Output
f() before str='Hello World'
f() after str='java'
main() before str='erlang'
f() before str='erlang'
f() after str='java'
main() after str='erlang'
As to OP's question:
C literals, where are these stored?
The location of a string literal is not defined in C. It might use the "process address space, within section constants", it might not. What is important is that an array is formed and the address of the first character is given in assignment to a const char *. Further detail: writing to this address is undefined behavior (UB), it may "work", fail, seg-fault, etc.
This would be more obvious if you changed the name of the argument for f...
#include <stdio.h>
void f(const char * foo) {
foo = "java";
}
int main (int argc, char * argv[]) {
const char *str = "erlang";
f(str);
printf("%s\n", str);
}
foo is a different variable to str. It has a different name, a different scope, and can contain a different value. The changes to foo won't propagate to str. If you wanted to modify str from within f, you would need to make f look like this:
void f(const char **foo) {
*foo = "java";
}
... and pass a pointer to str to f like so: f(&str);.
Did you happen to notice how I changed void main to int main? There are only two signatures for main entry points (excluding the equivalents) that are guaranteed by the standard to be portable:
int main(void) { /* ... */ }
... and ...
int main(int argc, char *argv[]) { /* ... */ }
Either way, main always returns int (or equivalent). This shouldn't inconvenience you too much, as in C99 (any half-decent compiler that's newer than fifteen years old) and C11 there's this little gem which allows you to omit return 0; from main:
If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument;11) reaching the } that terminates the main function returns a value of 0.
So if anything, your code using an int main entry point is not just portable but also one byte shorter than your code using a non-portable void main entry point.

Syntax for passing a const char parameter to static char *argv[] in C

Okay, I'm trying to build a daemon (for a Debian machine) that will take the command line arguments it receives (via cron) and pass them to different script files.
The daemon's main() is
int main(int argc , char *argv[])
{
if(argc != 3)
{
exit(0);
}
daemonize(argv[1], argv[2]);
return 0;
}
And the function daemonize has this set up
int daemonize(const char *cmd1, const char *cmd2) {...}
The troubling part in daemonize is here:
if (strcmp(cmd1,"sample_script") == 0)
{
static char *argv[] = {"/etc/init.d/sample_script", ["%s",cmd2], NULL };
execv("/etc/init.d/sample_script",argv);
exit(127);
}
On the line
static char *argv[] = {"/etc/init.d/sample_script", ("%s",cmd2), NULL };
I am getting this error
initializer element is not constant (near initialization for ‘argv[1]’)
Obviously ("%s",cmd2) is wrong. Because using "start" works fine.
So, how do I get cmd2 to be correctly put into *argv[]? Or is it something else I am doing wrong?
You need to change
static char *argv[] = {"/etc/init.d/sample_script", ["%s",cmd2], NULL };
to
const char *argv[] = {"/etc/init.d/sample_script", cmd2, NULL };
You have to remove the static keyword. As per chapter 6.7.9, C11 standard,
All the expressions in an initializer for an object that has static or thread storage duration
shall be constant expressions or string literals.
Which says, in C language objects with static storage duration have to be initialized with constant expressions or with aggregate initializers containing constant expressions.
And, regarding constant expression, from chapter 6.6 of the same document
A constant expression can be evaluated during translation rather than runtime, and
accordingly may be used in any place that a constant may be.
So, in C, a variable (name), even if declared as const is never a constant expression.
EDIT:
To resolve the latest issue, you can try the following
change int daemonize(char *cmd1, char *cmd2) {..
use char * const argv[] = {"/etc/init.d/sample_script", cmd2, NULL };
and you can keep the rest of the code unchanged.
The function declaration for execv is
int execv(const char *path, char *const argv[]);
The proper interpretation of the second argument is a "const array of char *", which is different than an "array of const char *". In other words, execv reserves the right to change the contents of the strings that the array points to, but won't change any of the pointers in the array.
Which is to say that all of the strings in the argv array must be in writable memory. So to be perfectly technically correct, the code should make writable copies of all the strings, like so
if (strcmp(cmd1,"sample_script") == 0)
{
char arg0[] = "/etc/init.d/sample_script";
char *arg1 = strdup( cmd2 );
char *argv[] = { arg0, arg1, NULL };
execv( argv[0], argv );
exit(127);
}
you can't initialize a static with a variable/argument only known at runtime.
leave the static out:
char *argv[] = {"/etc/init.d/sample_script", ["%s",cmd2], NULL };

Check if string can be mutated in C

Say I have this function:
void f(char *s) {
s[0] = 'x';
}
This function will sometimes cause errors and sometimes not. For example,
char *s = "test";
f(s); // Error
char t[] = "test";
f(t); // Success
Inside function f, is it possible to determine whether or not s[0] = 'x'; will cause an error before doing it?
The responsibility is on the caller to comply with requirements of the function that the argument be changeable, not the reverse.
const char *s = "test"; // tell compiler s is immutable
f(s); // compilation error since f() requires a non-const argument
char t[] = "test";
f(t); // Success
The only way to stop the compiler from rejecting f(s) in the above is to either remove the const from the declaration of s, or to cast the const'ness away. Except in exceedingly rare circumstances, both are positive indicators of a problem.
Note: it is an anomaly in the language that s can be declared without the const qualifier. Get in the practice of using const where needed (e.g. when initialisating a pointer using a string literal). A lot of program bugs are eliminated that way.
Given the feedback I've received, It sounds like I should instead document whether or not the function requires its arguments to be mutable. For example:
#include <stdio.h>
#include <string.h>
char* f(char*);
void g(char*);
int main(int argc, char *argv[]) {
// s is immutable.
char *s = "test";
puts(f(s));
// t is mutable.
char t[] = "test";
g(t);
puts(t);
}
/*
* Returns a copy of the given string where the first character is replaced with 'x'.
* Parameter s must contain at least one character.
*/
char* f(char *s) {
char *t = strdup(s);
t[0] = 'x';
return t;
}
/*
* Replaces the first character of the given sting with 'x'.
* Parameter s must contain at least one character and be mutable.
*/
void g(char *s) {
s[0] = 'x';
}

C Storage Size Isn't a Constant...why?

Here's the simple example program
#include <stdio.h>
#include <string.h>
const char *hello_string = "Hello";
int main(void)
{
char *world_string = " World";
static char hello_world[strlen(hello_string)+strlen(world_string)];
strcpy(&hello_world[0], hello_string);
strcat(&hello_world[0], world_string);
printf("%s\n", hello_world);
return 0;
}
The compiler output:
test.c: In function ‘main’:
test.c:9:13: error: storage size of ‘hello_world’ isn’t constant
static char hello_world[strlen(hello_string)+strlen(world_string)];
^
I realize the completely useless and unnecessary use of "static" in this case causes the error and with its removal things will compile fine. This is just a simple example to illustrate my question.
What I don't understand is why the storage size is not a constant when the "hello_string" is declared as const char * and its size is not going to change during the course of execution. Is this just a case of the compiler not being smart enough to know that?
When the compiler complains about storage size not being constant implicitly means compile-time constant, i.e. a value that the compiler can determine at compile-time. The call of strlen obviously would happen at runtime, so the compiler cannot know the size of your array.
Try this:
#include <stdio.h>
#include <string.h>
const char hello_string[] = "Hello";
int main(void)
{
char world_string[] = " World";
static char hello_world[sizeof hello_string + sizeof world_string];
strcpy(&hello_world[0], hello_string);
strcat(&hello_world[0], world_string);
printf("%s\n", hello_world);
return 0;
}
strlen is a function. It's return value cannot be calculated at compile time.
You used the static storage class speficier in your array declaration.
static arrays can only have fixed length: i.e., the size of the array has to be an integer constant expression. An expression involving a function call is not a constant expression.
Remove the static specifier if you want to use a variable length array. And then don't forget to reserve an extra character in your array for the null terminator.
strlen() is a function call. The compiler doesn't know what it does.
Try sizeof (*hello_string). I'm not sure whether that would work.
Or const char hello_string[] = "Hello" and sizeof(hello_string), which seems to me more likely to work.

Resources