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.
Related
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.
I have a simple program as below:
static const char* DeviceID = (char*)"my id";
int length = strlen(DeviceID);
int main(){
}
and the compiler throw the following error:
initializer element is not constant
I don't know why the compiler can't understand my statement:
strlen's prototype is like the following code:
size_t strlen ( const char * str );
Try sizeof which yields a compile time constant
#define MY_ID "my id"
static const char *DeviceID = MY_ID; // no cast needed
int length = sizeof MY_ID - 1; // sizeof also includes the '\0'
int main(void) {
/* ... */
}
As far as I know, there is different with C and C++ when you're trying to initailize global variables.
in C, Rvalue of the global initializing statement should be evaluated at compile time.
for instance,
static const char* DeviceID = (char*)"my id"; <-- compiler can evaluate address of "my_id". so, this is valid.
int length = strlen(DeviceID); <-- but this can't be at compiletime. means that, we should run the process in order to know
its value.
But, C++ doesn't care about like above. it can initialize global ones at runtime.
so if you use C++ compiler instead of, errors'll be disappeared.
I come from Java background and trying to understand C structures, pointers and arrays better. Here's the sample code that I am playing with:
If the following works:
#include <stdio.h>
int main(void) {
char string[] = "Hello";
printf("%c",string[0]);
return 0;
}
Why does the following return with an error?
#include <stdio.h>
int main(void) {
typedef struct{
int x;
char string[8];
}ST_DATA;
ST_DATA *my_data;
my_data->x = 100;
my_data->string = "Hello"; // issues a warning, described below
printf("%d",my_data->x); // works fine
printf("%c",my_data->string[0]);
return 0;
}
Following is the error that I am getting:
Compilation error time: 0 memory: 2292 signal:0
prog.c: In function ‘main’:
prog.c:12:18: error: incompatible types when assigning to type ‘char[8]’ from type ‘char *’
my_data->string = "Hello";
I tried with the following changes as well:
a)
my_data->string[] = "Hello";
This will give me the following error:
prog.c: In function ‘main’:
prog.c:12:18: error: expected expression before ‘]’ token
my_data->string[] = "Hello";
^
b)
my_data->string[8] = "Hello";
This returns with a runtime error. Presumably, the error occurs when I am printing the first character.
There must be something stupid that I am doing or expecting (being used to coding with other languages than C), but I can't seem to figure out why this is happening and how to get it to work. I'd greatly appreciate any pointers (ha! get it?)
In your first case, you are automatically allotting memory for char string[] = "Hello". The compiler takes care of memory management here.
In the second, my_data is a pointer and you need to allot memory to it manually, before you assign something to it.
You can:
ST_DATA *my_data = (ST_DATA *)malloc(sizeof(ST_DATA));
It'd be good you spend some time reading about automatic memory allocation and dynamic memory allocation.
strcpy() need to be used to copy strings into string members of structure ST_DATA.
strcpy(my_data->string, "Hello");
Before you have to allocate memory for your structure as,
ST_DATA *my_data = (ST_DATA *) malloc(sizeof(ST_DATA));
EDIT: The structure ST_DATA inside main() is just a declaration which tells compiler that it has members of what type they are. How can you use it until it is allocated memory. You can think ST_DATA as a data type similar to any other data types as int etc which has no meaning when they are not defined as int object which gets memory for i.
ST_DATA *my_data;
my_data->x = 100;
here my_data is a pointer so first allocate memory to it.
char string[] = "Hello";
here string is assigned value with declaration so it if fine. but in next code
my_data->string = "Hello";
is not ok since initialization can be done only with declaration. after declaration for string value has to be assigned using strcpy()
I just started to look at C, coming from a java background. I'm having a difficult time wrapping my head around pointers. In theory I feel like I get it but as soon as I try to use them or follow a program that's using them I get lost pretty quickly. I was trying to follow a string concat exercise but it wasnt working so I stripped it down to some basic pointer practice. It complies with a warning conflicting types for strcat function and when I run it, crashes completly.
Thanks for any help
#include <stdio.h>
#include <stdlib.h>
/* strcat: concatenate t to end of s; s must be big enough */
void strcat(char *string, char *attach);
int main(){
char one[10]="test";
char two[10]="co";
char *s;
char *t;
s=one;
t=two;
strcat(s,t);
}
void strcat(char *s, char *t) {
printf("%s",*s);
}
Your printf() should look like this:
printf("%s",s);
The asterisk is unnecessary. The %s format argument means that the argument should be a char*, which is what s is. Prefixing s with * does an extra invalid indirection.
You get the warning about conflicting types because strchr is a standard library routine, which should have this signature:
char * strcat ( char * destination, const char * source );
Yours has a different return type. You should probably rename yours to mystrchr or something else to avoid the conflict with the standard library (you may get linker errors if you use the same name).
Change
printf("%s",*s);
to
printf("%s",s);
The reason for this is printf is expecting a replacement for %s to be a pointer. It will dereference it internally to get the value.
Since you declared s as a char pointer (char *s), the type of s in your function will be just that, a pointer to a char. So you can just pass that pointer directly into printf.
In C, when you dereference a pointer, you get the value pointed to by the pointer. In this case, you get the first character pointed to by s. The correct usage should be:
printf( "%s", s );
BTW, strcat is a standard function that returns a pointer to a character array. Why make your own?
Replacing *s with s won't append strings yet, here is fully working code :
Pay attention to function urstrcat
#include <stdio.h>
#include <stdlib.h>
/* urstrcat: concatenate t to end of s; s must be big enough */
void urstrcat(char *string, char *attach);
int main(){
char one[10]="test";
char two[10]="co";
char *s;
char *t;
s=one;
t=two;
urstrcat(s,t);
return 0;
}
void urstrcat(char *s, char *t) {
printf("%s%s",s,t);
}
pointers are variable which points to address of a variable.
#include "stdio.h"
void main(){
int a,*b;
a=10;
b=&a;
printf("%d",b);
}
in the follwing code you will see a int 'a' and a pointer 'b'.
here b is taken as pointer of an integer and declared by giving'' before it.'' declare that 'b' is an pointer.then you will see "b=&a".this means b is taking address of integer "a" which is keeping value 10 in that particular memory and printf is printing that value.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *abc = "abc";
char *new_str;
new_str = getStr(&abc);
printf("%s", abc);
}
char *getStr(char *str)
{
printf(str);
return str;
}
What's wrong with the code above?
A bunch of small things:
You're passing &abc to getStr(). &abc is a pointer to the variable that is holding your string. Its type a pointer to a pointer, and that's incompatible with the char *str argument of getStr().
Your getStr() is defined after it is used. You either need to move its definition to before main() or add a prototype before main().
The type of a string literal like "abc" is const char *. You're defining a variable of type char *, which is dubious (since it would allow you to modify a string literal, which is not allowed).
here is a working version:
#include <stdio.h>
#include <stdlib.h>
char *getStr(char *str);
int main(void)
{
char *abc = "abc";
char *new_str;
new_str = getStr(abc);
//printf("%s", *abc); don't really need this
}
char *getStr(char *str) {
printf("%s", str);
return str;
}
Here's a list of problems with the old one:
No prototype for your function getStr.
You can't do printf(str) you need a "%s" as an additional param.
You need to change: new_str = getStr(&abc) to new_str = getStr(abc)
A C string is a pointer to a character that begins a sequence of characters that end with a null byte. The variable abc perfectly fits this definition.
Also, abc is of type pointer to character. You are passing the address of abc, ie getStr will be receiving the address of a pointer to a character--so getStr's only argument should be of type pointer to pointer to character. The types do not match up.
EDIT: Also, getStr is called before it's declared. Your compiler may allow this, but it's bad practice for many reasons. You should declare it or define it before it is used. If you are using gcc as your compiler, always use
gcc -ansi -Wall -pedantic
Those three flags will conform to ANSI standards, and it would either yell at you for the above issues or not compile.
Your getStr function takes a char *, but that's not what you're passing it - you're passing the address of the pointer, instead of passing it the actual pointer.
Change:
new_str = getStr(&abc);
to:
new_str = getStr(abc);
and I think it'll work.