What is the difference between string literals and a pointer? - c

Generally, you can initialize a pointer with any string literals like char *str = "Hello". I think this means "Hello" returns the address of 'H'. However, the below isn't allowed.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[64];
} Student;
Student initialization(char *str) {
//Student tmp = {}; strcpy(tmp.name, str) //(*1)This is allowed.
//Student tmp = {"Hello"}; //(*2)This is allowed.
Student tmp = {str}; //(*3)This is not allowed.
return tmp;
}
int main(void) {
(...)
}
Could anyone tell me the reason why (*2) is allowed but (*3) is not allowed? Compiling this code makes the error below.
warning: initialization makes integer from pointer without a cast [-Wint-conversion]
Student tmp = {str};
^

All these cases you are trying to initialize a char array. Now after saying that - we can see it makes thing easier. Just like an char array where if we write down a string literal directly it initializes the char array with the content of the string literal.
But in the second case, the string literal which is basically a char array is converted to a pointer to the first element of it (the fist character of string literal) which is then used to initialize the char array. That will not work. Note that, even if str is a pointer to a char array which is not a literal this won't work. For the same reason as specified. Standard allows initialization from the string literal directly. Not other way round.
From standard 6.7.9p14
An array of character type may be initialized by a character string literal or UTF-8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

Related

String vs String Literal: Direct assignment or strcpy/strncpy?

I think I have some issue understanding string and string literal.
This is what I learned from my class, when passing to a function, const char * indicates this is a string literal, while char * indicates a string.
Suppose I have a struct declaration:
struct node{
char *name;
struct node *next;
};
and a function, this is the function I want to implement:
void load_buffer(struct node *input_node, char *input_name);
This function is supposed to assign input_name to the struct's member name.
My confusion comes from here. Within the body of load_buffer, should I write:
input_node->name = input_name;
Or I should use strcpy/strncpy to do this?
strcpy(input_node->name, input_name);// Suppose it's safe in this case.
To summarize, I am not sure if I should use direct assignment or strcpy family functions to assign a string/string literal to the member of my struct.
Thanks for help. :)
In case of pointer assignment, pointers in each node will point to same location. Thus nodes will be always pointing to updated value. If you are intended to make each node to contain different input then this approach does not suit your requirement.
input_node->name = input_name;
In case of strcpy, pointers in each node will point to different location. Before to that you need to create memory for each pointer.
input_node->name = malloc(strlen(input_name)+1); //Allocate memory first.
strcpy(input_node->name, input_name);// Suppose it's safe in this case.
To visualize:
... when passing to a function, const char * indicates this is a string literal, while char * indicates a string.
Not exactly. const char * declares that the function will not try to modify the string. So it is perfectly suited for string litteral because they cannot be modified.
For your question, the answer is it depends on your real requirements. But simply storing the passed pointer if dangerous if the struct can persist after the function and if the string can be changed in the caller. Let us look at the following code:
void load_buffer(struct node *input_node, const char *input_name) {
input_node->name = name;
}
struct node nodes[2];
char buf[4];
const char *data[] = { "foo", "bar"};
for (int i=0; i<2; i++) {
strcpy(buf, data[i]); // suppose it is read from somewhere (file, stdin, socket)
load_buffer(node + i, buf);
}
Both node objects will have their name member pointing to the string buf from caller and will both point to "bar" (the content of buf at the end of the loop)!
If you want to keep the value of the string at call time, you should copy it in allocated memory:
void load_buffer(struct node *input_node, const char *input_name) {
input_node->name = strdup(name); // allocation errors should be tested...
}
But you should then free the name member, when the node is no longer in use...
First to address some terminology:
this is a string literal: "I am a string literal"
this is a type: char* (aka pointer to char)
this is also a type: const char* (aka pointer to constant char)
this is the declaration of a variable of type char*: char* str
this is the declaration of a variable of type const char*: const char* cstr
A pointer is not a string literal. A pointer can point to string literal, an array, just to a single element or can be null.
In C a string is a null-terminated char array.
In C you can assign a char* variable to a string literal, but modifying the string literal is illegal, so it is strongly advised to never do that. The reason why this is allowed are historical.
char* a = "asd"; // allowed, but frowned upon
// a points to a string literal, so we can say a is a string
// a is not a string literal
char b = 'x';
char* c = &b;
// c points to a single char
// we cannot say c is a string
char d[10] = "asd";
// d is a char array. Its content is a string, so we can say d is a string.
// d is not a string literal
// the string literal is copied into the array d
char* e = d; // or equivalent char* e = &d[0];
// e points to a string
char f[4] = {'a', 's', 'd', '\0'};
// f is an array. Its content is a string, so we can say f is a string
char* g = f;
// g points to a string. We can say g is a string
char h[3] = {'a', 's', 'd'};
// h is an array. Its content is NOT a string, because the char array is not null terminated
char* i = h;
// i is not a string
And now go through all the above once more, but not replace char with const char and all the comments still stand (except that `const char* a = "asd" is now ok).
And now to the problem at hand.
There are two scenarios:
Each node has its own string and "owns" that string. Each node is responsible for allocating memory for the string and freeing that memory. The string lives as long as the node lives. In this case use malloc and strcpy to create a string for each node. Don't forget to free the string when the node is destroyed. This is the most common scenario and probably what you want.
A node doesn't own its own string, but rather points to an external string. It is not allowed to neither allocate nor free memory for that string. There is another entity responsible for managing the lifetime of that string and making sure the string is alive at least as the node is alive. The string can outlive the node without a memory leak.
For example consider this scenario:
there is a list R of string resources. This list owns those resources. This list would use scenario 1
we need to keep two different sort orders of R. So we have two lists A and B that would use scenario 2: each node in A and B just points to a string of R.

variable of type 'const char *' cannot be assigned to entity of type 'char'

The program is as follows
typedef struct Signal {
long int vr[4];
char name[4];
char Type;
char casuality[2];
};
and I wanted to use this structure in such way where for eg: for variable vr I am able to do vr[0]=1073741824 but for casuality if I assign casuality[0]="output" it is showing error as given above
void xmlRead()
{
struct FMU *fmu;
struct Signal *var;
struct Signal iname;
(*var).vr[0]=1073741824;
(*var).vr[1]=1073741825;
(*var).vr[2]=1073741826;
(*var).vr[3]=1073741827;
(iname).name[0]="Ball1_pos"; //Here it is showing the error//
}
In your case, "output" is a string literal, having type char [7] and casuality[0] is of type char.
Obviously, they are not compatible (one is an array, the other a simple char) and hence the error.
There are two ways to achieve what you want,
Change char casuality[2]; to char *casuality[2]; then the assignment will work fine (however, you can't modify a string literal).
Allocate an array long enough and use strcpy() to copy the content of the string literal into the array.
You are trying to assign a string literal (made of several chars), to the first location of an array of four chars (Signal.name[0]).
// a single char = a string literal, i.e., from const char* to char
(iname).name[0] = "Ball1_pos";
This is obviously incompatible in types.
Note that even if the string literal was short enough to be fit into the memory spanned by the variable name, you would need a function such as strcpy or memcpy to assign the value to that memory.
In particular, something like the following would work:
strcpy(iname.name, "abc")
(note that string literals are null terminated by the compiler and strcpy includes the \0)
To make things (hopefully) more clear for you, the following would be equivalent:
iname.name[0] = 'a'
iname.name[1] = 'b'
iname.name[2] = 'c'
iname.name[3] = '\0'

difference between string pointer and string array

I was writing code to reinforce my knowledge, I got segmentation fault. So, I also got that I have to restock(completing imperfect knowledge) on my knowledge. The problem is about strtok(). When I run the first code there is no problem, but in second, I get segmantation fault. What is my "imperfect knowledge" ? Thank you for your appreciated answers.
First code
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "team_name=fenerbahce";
char *token;
token = strtok(str,"=");
while(token != NULL)
{
printf("%s\n",token);
token = strtok(NULL,"=");
}
return 0;
}
Second code
#include <stdio.h>
#include <string.h>
int main() {
char *str= "team_name=fenerbahce";
char *token;
token = strtok(str,"=");
while(token != NULL)
{
printf("%s\n",token);
token = strtok(NULL,"=");
}
return 0;
}
From strtok -
This function is destructive: it writes the '\0' characters in the elements of the string str. In particular, a string literal cannot be used as the first argument of strtok.
And in the second case, str is a string literal which resides in read only memory. Any attempt to modify string literals lead to undefined behavior.
You see string literals are the strings you write in "". For every such string, no-matter where it is used, automatically a global space is alloacted to store it. When you assign it to an array - you copy it's content into a new memory, that of the array. Otherwise you just store a pointer to it's global memory storage.
So this:
int main()
{
const char *str= "team_name=fenerbahce";
}
Is equal to:
const char __unnamed_string[] { 't', 'e', /*...*/, '\0' };
int main()
{
const char *str= __unnamed_string;
}
And when assigning the string to array, like this:
int main()
{
char str[] = "team_name=fenerbahce";
}
To this:
const char __unnamed_string[] { 't', 'e', /*...*/, '\0' };
int main()
{
char str[sizeof(__unnamed_string) / sizeof(char)];
for(size_t i(0); i < sizeof(__unnamed_string) / sizeof(char); ++i)
str[i] = __unnamed_string[i];
}
As you can see there is a difference. In the first case you're just storing a single pointer and in the second - you're copying the whole string into local.
Note: String literals are un-editable so you should store their address at a constant.
In N4296 - § 2.13.5 .8 states:
Ordinary string literals and UTF-8 string literals are also referred
to as narrow string literals. A narrow string literal has type “array
of n const char”, where n is the size of the string as defined below,
and has static storage duration
The reason behind this decision is probably because this way, such arrays can be stored in read-only segments and thus optimize the program somehow. For more info about this decision see.
Note1:
In N4296 - § 2.13.5 .16 states:
Evaluating a string-literal results in a string literal object with
static storage duration, initialized from the given characters as
specified above.
Which means exactly what I said - for every string-literal an unnamed global object is created with their content.
char *str= "team_name=fenerbahce";
char str[]= "team_name=fenerbahce";
The "imperfect" knowledge is about the difference between arrays and pointers! It's about the memory you cannot modify when you create a string using a pointer.
When you create a string you allocate some memory that will store those values (the characters of the string). In the next lines I will refer to this when I'll talk about the "memory allocated at the start".
When you create a string using an array you will create an array that will contain the same characters as the ones of the string. So you will allocate more memory.
When you create a string using a pointer you will point to the address of memory that contains that string (the one allocated at the start).
You have to assume that the memory created at the start is not writable (that's why you'll have undefined behavior, which means segmentation fault most of the times so don't do it).
Instead, when you create the array, that memory will be writable! That's why you can modify with a command like strtok only in this case

difference between character array initialized with string literal and one using strcpy

Please help me understand what is the difference using an initialized character array like char line[80]="1:2" ( which doesn't work !! ) and using char line[80] followed by strcpy(line,"1:2").
As per my understanding in first case I have a charachter array, it has been allocated memory, and i am copying a string literal to it. And the same is done in the second case. But obviously I am wrong. So what is wrong with my understanding.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void tokenize(char* line)
{
char* cmd = strtok(line,":");
while (cmd != NULL)
{
printf ("%s\n",cmd);
cmd = strtok(NULL, ":");
}
}
int main(){
char line[80]; //char line[80]="1:2" won't work
/*
char *line;
line = malloc(80*sizeof(char));
strcpy(line,"1:2");
*/
strcpy(line,"1:2");
tokenize(line);
return 0;
}
You are wrong. The result of these two code snippets
char line[80] = "1:2";
and
char line[80];
strcpy( line, "1:2" );
is the same. That is this statement
char line[80] = "1:2";
does work.:)
There is only one difference. When the array is initialized by the string literal all elements of the array that will not have a corresponding initialization character of the string literal will be initialized by '\0' that is they will be zero-initialized. While when function strcpy is used then the elements of the array that were not overwritten by characters of the string literal will have undeterminated values.
The array is initialized by the string literal (except the zero initialization of its "tail") the same way as if there was applied function strcpy.
The exact equivalence of the result exists between these statements
char line[80] = "1:2";
and
char line[80];
strncpy( line, "1:2", sizeof( line ) );
that is when you use function strncpy and specify the size of the target array.
If you mean that you passed on to function tokenize directly the string literal as an argument of the function then the program has undefined behaviour because you may not change string literals.
According to the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.

string literal in c

Why is the following code illegal?
typedef struct{
char a[6];
} point;
int main()
{
point p;
p.a = "onetwo";
}
Does it have anything to do with the size of the literal? or is it just illegal to assign a string literal to a char array after it's declared?
It doesn't have anything to do with the size. You cannot assign a string literal to a char array after its been created - you can use it only at the time of definition.
When you do
char a[] = "something";
it creates an array of enough size (including the terminating null) and copies the string to the array. It is not a good practice to specify the array size when you initialize it with a string literal - you might not account for the null character.
When you do
char a[10];
a = "something";
you're trying to assign to the address of the array, which is illegal.
EDIT: as mentioned in other answers, you can do a strcpy/strncpy, but make sure that the array is initialized with the required length.
strcpy(p.a, "12345");//give space for the \0
You can never assign to arrays after they've been created; this is equally illegal:
int foo[4];
int bar[4];
foo = bar;
You need to use pointers, or assign to an index of the array; this is legal:
p.a[0] = 'o';
If you want to leave it an array in the struct, you can use a function like strcpy:
strncpy(p.a, "onetwo", 6);
(note that the char array needs to be big enough to hold the nul-terminator too, so you probably want to make it char a[7] and change the last argument to strncpy to 7)
Arrays are non modifiable lvalues. So you cannot assign to them. Left side of assignment operator must be an modifiable lvalue.
However you can initialize an array when it is defined.
For example :
char a[] = "Hello World" ;// this is legal
char a[]={'H','e','l','l','o',' ','W','o','r','l','d','\0'};//this is also legal
//but
char a[20];
a = "Hello World" ;// is illegal
However you can use strncpy(a, "Hello World",20);
As other answers have already pointed out, you can only initialise a character array with a string literal, you cannot assign a string literal to a character array. However, structs (even those that contain character arrays) are another kettle of fish.
I would not recommend doing this in an actual program, but this demonstrates that although arrays types cannot be assigned to, structs containing array types can be.
typedef struct
{
char value[100];
} string;
int main()
{
string a = {"hello"};
a = (string){"another string!"}; // overwrite value with a new string
puts(a.value);
string b = {"a NEW string"};
b = a; // override with the value of another "string" struct
puts(b.value); // prints "another string!" again
}
So, in your original example, the following code should compile fine:
typedef struct{
char a[6];
} point;
int main()
{
point p;
// note that only 5 characters + 1 for '\0' will fit in a char[6] array.
p = (point){"onetw"};
}
Note that in order to store the string "onetwo" in your array, it has to be of length [7] and not as written in the question. The extra character is for storing the '\0' terminator.
No strcpy or C99 compund literal is needed. The example in pure ANSI C:
typedef struct{
char a[6];
} point;
int main()
{
point p;
*(point*)p.a = *(point*)"onetwo";
fwrite(p.a,6,1,stdout);fflush(stdout);
return 0;
}

Resources