I'm trying to understand how to solve this trivial problem in C, in the cleanest/safest way. Here's my example:
#include <stdio.h> int main(int argc, char *argv[]) { typedef struct { char name[20]; char surname[20]; int unsigned age; } person; // Here I can pass strings as values...how does it work? person p = {"John", "Doe", 30}; printf("Name: %s; Age: %d\n", p.name, p.age); // This works as expected... p.age = 25; //...but the same approach doesn't work with a string p.name = "Jane"; printf("Name: %s; Age: %d\n", p.name, p.age); return 1; }
The compiler's error is:
main.c: In function ‘main’: main.c:18: error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’
I understand that C (not C++) doesn't have a String type and instead uses arrays of char
s, so another way to do this was to alter the example struct to hold pointers of char
s:
#include <stdio.h> int main(int argc, char *argv[]) { typedef struct { char *name; char *surname; int unsigned age; } person; person p = {"John", "Doe", 30}; printf("Name: %s; Age: %d\n", p.name, p.age); p.age = 25; p.name = "Jane"; printf("Name: %s; Age: %d\n", p.name, p.age); return 1; }
This works as expected, but I wonder if there a better way to do this.
strcpy(p.name, "Jane"); to change its content, the address of the buffer p.name[] never changes. An interesting parallel between C and Python is that Python's String is immutable and is similar to C's string pointer where string literals are read-only. Python's List is mutable and is similar to C's character array.
The first example doesn't work because you can't assign values to arrays - arrays work (sort of) like const pointers in this respect. What you can do though is copy a new value into the array:
strcpy(p.name, "Jane");
Char arrays are fine to use if you know the maximum size of the string in advance, e.g. in the first example you are 100% sure that the name will fit into 19 characters (not 20 because one character is always needed to store the terminating zero value).
Conversely, pointers are better if you don't know the possible maximum size of your string, and/or you want to optimize your memory usage, e.g. avoid reserving 512 characters for the name "John". However, with pointers you need to dynamically allocate the buffer they point to, and free it when not needed anymore, to avoid memory leaks.
Update: example of dynamically allocated buffers (using the struct definition in your 2nd example):
char* firstName = "Johnnie"; char* surname = "B. Goode"; person p; p.name = malloc(strlen(firstName) + 1); p.surname = malloc(strlen(surname) + 1); p.age = 25; strcpy(p.name, firstName); strcpy(p.surname, surname); printf("Name: %s; Age: %d\n",p.name,p.age); free(p.surname); free(p.name);
Think of strings as abstract objects, and char arrays as containers. The string can be any size but the container must be at least 1 more than the string length (to hold the null terminator).
C has very little syntactical support for strings. There are no string operators (only char-array and char-pointer operators). You can't assign strings.
But you can call functions to help achieve what you want.
The strncpy()
function could be used here. For maximum safety I suggest following this pattern:
strncpy(p.name, "Jane", 19); p.name[19] = '\0'; //add null terminator just in case
Also have a look at the strncat()
and memcpy()
functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With