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.
Related
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.
I have a pointer:
char * name;
it contains the string "test:case"
And I'm calling another function with it, and trying to store it in a structure. However, I want to capitalize the entire string first, but It doesn't seem to work.
void func(char * name) {
int i;
List * l;
l = malloc(sizeof(List));
for(i=0; i< strlen(name); i++) {
name[i] = toupper(name[i]);
}
l->name = name;
//CALL A FUNCTION TO LATER FREE ALLOCATED MEMORY
}
Where List is a struct that has a member (char *) named name.
This however, seg faults. I can't go about using non pointers in my case. As I have to use pointers and not character arrays, I'm trying to use toupper in every value of the char pointer, however this doesn't seem to work.
You're getting a segfault because the original string is presumably a literal, and it's not modifiable. You need to make a copy of it first.
void func(char * name) {
List * l;
l = malloc(sizeof(List));
name = strdup(name); // make a copy of name
for (char *p = name; *p; p++) {
*p = toupper(*p);
}
l->name = name;
}
Note that when you later free l, you'll first need to free l->name.
Since you only set the pointer l->name to name, this will crash the moment the original name is no longer there (maybe it was only on the stack?) and l->name is accessed. You need to malloc() space the size of strlen(name)+1, copy name there and set l->name to that address.
You have allocated the List, but not the name string itself.
You need to do:
l=malloc(sizeof(List));
l->name=(char*)malloc(strlen(name)+1); // You need to cater for the the final null char.
There are a few additional issues with your code, here is the correct one (didn't compile it, probably close to okay):
void func(char *name) {
List * l;
l = (List*)malloc(sizeof(List));
l->name = (char*)malloc(strlen(name)+1);
for(char *r=name, char *w=l->name; *r; ++r,++w) {
*w = toupper(*r);
}
*++w='\0';
}
And at every iteration, this code does not evaluate again and again strlen, which would be very bad.
There are two mistakes in the code.
char * name
The variable name contains a pointer to a string (i.e., an array of char).
When you write this:
name[i] = toupper(name[i]);
you are changing the original char itens of the string, if it is not a pointer to a constant string. If that is the case, it is a segmentation fault.
The other mistake is here:
l->name = name;
You are just assigning to the variable within the structure the pointer which was passed on through the variable name to the function. You should make a copy, like this:
strcpy(l->name, name);
This functions copies all the contents from the second argument to the first.
But that's not a good solution. If name contains a pointer to a constant string, it's still segmentation fault.
I'll rewrite your code:
void func(char * name) {
int i;
List * l;
l = malloc(sizeof(List));
char *buffer[strlen(name)]; //buffer of the contents pointed by *name* to upper case, initialized as empty string
for(i=0; i< strlen(name); i++) {
buffer[i] = toupper(name[i]);
}
buffer[i] = '\0'; //closing the string in i = strlen(name)
strcpy(l->name, buffer);
//CALL A FUNCTION TO LATER FREE ALLOCATED MEMORY
}
That way, you manipulate a copy of the original string, and than you make a copy of the buffer to the variable in the structure.
If you do this:
l->name = buffer;
you're only copying a local pointer, which will be gone with the end of the function.
I suggest you learn more about pointers, arrays and strings in C. In essence, a string is a array of char, with a '\0' in the final position. An empty string s has '\0' in s[0].
Edit: if you're used to languages which makes a copy of the string like this:
string1 = string2
you should always have in mind that, in C, that's pointer assignment. So, in C, that code would have to be written like this:
strcpy(string1, string2);
Hope that helps.
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'
In a program I am writing I made a Tokenize struct that says:
TokenizerT *Tokenize(TokenizerT *str) {
TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));
const char *s = str->input_strng;
int i = 0;
char *ds = malloc(strlen(s) + 1);
strcpy(ds, s);
*tok->array[i] = strtok(ds, " ");
while(*tok->array[i]) {
*tok->array[++i] = strtok(NULL, " ");
}
free(ds);
return tok;
}
where TokenizeT is defined as:
struct TokenizerT_ {
char * input_strng;
int count;
char **array[];
};
So what I am trying to do is create smaller tokens out of a large token that I already created. I had issues returning an array so I made array part of the TokenizerT struct so I can access it by doing tok->array. I am getting no errors when I build the program, but when I try to print the tokens I get issues.
TokenizerT *ans;
TokenizerT *a = Tokenize(tkstr);
char ** ab = a->array;
ans = TKCreate(ab[0]);
printf("%s", ans->input_strng);
TKCreate works because I use it to print argv but when i try to print ab it does not work. I figured it would be like argv so work as well. If someone can help me it would be greatl appreciated. Thank you.
Creating the Tokenizer
I'm going to go out on a limb, and guess that the intent of:
TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));
was to dynamically allocate a single TokenizerT with the capacity to contain 49 strings and a NULL endmarker. arr is not used anywhere in the code, and tok is never given a value; it seems to make more sense if the values are each shifted one statement up, and corrected:
// Note: I use 'sizeof *tok' instead of naming the type because that's
// my style; it allows me to easily change the type of the variable
// being assigned to. I leave out the parentheses because
// that makes sure that I don't provide a type.
// Not everyone likes this convention, but it has worked pretty
// well for me over the years. If you prefer, you could just as
// well use sizeof(TokenizerT).
TokenizerT *tok = malloc(sizeof *tok);
// (See the third section of the answer for why this is not *tok->array)
tok->array = malloc(50 * sizeof *tok->array);
(tok->array is not a great name. I would have used tok->argv since you are apparently trying to produce an argument vector, and that's the conventional name for one. In that case, tok->count would probably be tok->argc, but I don't know what your intention for that member is since you never use it.)
Filling in the argument vector
strtok will overwrite (some) bytes in the character string it is given, so it is entirely correct to create a copy (here ds), and your code to do so is correct. But note that all of the pointers returned by strtok are pointers to character in the copy. So when you call free(ds), you free the storage occupied by all of those tokens, which means that your new freshly-created TokenizerT, which you are just about to return to an unsuspecting caller, is full of dangling pointers. So that will never do; you need to avoid freeing those strings until the argument vector is no longer needed.
But that leads to another problem: how will the string be freed? You don't save the value of ds, and it is possible that the first token returned by strtok does not start at the beginning of ds. (That will happen if the first character in the string is a space character.) And if you don't have a pointer to the very beginning of the allocated storage, you cannot free the storage.
The TokenizerT struct
char is a character (usually a byte). char* is a pointer to a character, which is usually (but not necessarily) a pointer to the beginning of a NUL-terminated string. char** is a pointer to a character pointer, which is usually (but not necessarily) the first character pointer in an array of character pointers.
So what is char** array[]? (Note the trailing []). "Obviously", it's an array of unspecified length of char**. Because the length of the array is not specified, it is an "incomplete type". Using an incomplete array type as the last element in a struct is allowed by modern C, but it requires you to know what you're doing. If you use sizeof(TokenizerT), you'll end up with the size of the struct without the incomplete type; that is, as though the size of the array had been 0 (although that's technically illegal).
At any rate, that wasn't what you wanted. What you wanted was a simple char**, which is the type of an argument vector. (It's not the same as char*[] but both of those pointers can be indexed by an integer i to return the ith string in the vector, so it's probably good enough.)
That's not all that's wrong with this code, but it's a good start at fixing it. Good luck.
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;
}