¿Cómo asignar correctamente un nuevo valor de cadena?

Estoy tratando de entender cómo resolver este problema trivial en C, de la manera más limpia / más segura. Aquí está mi ejemplo:

#include  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 works? 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; } 

El error del comstackdor es:

main.c: en la función ‘main’: main.c: 18: error: tipos incompatibles al asignar a ‘char [20]’ del tipo ‘char *’

Entiendo que C (no C ++) no tiene ningún tipo de cadena y en su lugar utiliza matrices de caracteres, por lo que otra forma de hacerlo es modificar la estructura de ejemplo para contener punteros de caracteres:

 #include  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; } 

Esto funciona como se esperaba, pero me pregunto si hay una mejor manera de hacerlo. Gracias.

El primer ejemplo no funciona porque no se pueden asignar valores a las matrices: las matrices funcionan (algo así como) const punteros a este respecto. Sin embargo, lo que puedes hacer es copiar un nuevo valor en la matriz:

 strcpy(p.name, "Jane"); 

Los arrays de Char están bien para usar si conoce el tamaño máximo de la cadena de antemano, por ejemplo, en el primer ejemplo, está 100% seguro de que el nombre encajará en 19 caracteres (no 20 porque siempre se necesita un carácter para almacenar el cero de terminación) valor).

Por el contrario, los punteros son mejores si no conoce el tamaño máximo posible de su cadena, y / o desea optimizar su uso de memoria, por ejemplo, evite reservar 512 caracteres para el nombre “John”. Sin embargo, con los punteros es necesario asignar dinámicamente el búfer al que apuntan, y liberarlo cuando ya no sea necesario, para evitar pérdidas de memoria.

Actualización: ejemplo de búferes asignados dinámicamente (usando la definición de estructura en su segundo ejemplo):

 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); 

Piense en cadenas como objetos abstractos y matrices char como contenedores. La cadena puede ser de cualquier tamaño, pero el contenedor debe ser al menos 1 más que la longitud de la cadena (para mantener el terminador nulo).

C tiene muy poco soporte sintáctico para cadenas. No hay operadores de cadenas (solo operadores de matriz de caracteres y operadores de caracteres). No puedes asignar cadenas.

Pero puede llamar a funciones para ayudar a lograr lo que desea.

La función strncpy() podría usarse aquí. Para mayor seguridad, sugiero seguir este patrón:

 strncpy(p.name, "Jane", 19); p.name[19] = '\0'; //add null terminator just in case 

También eche un vistazo a las strncat() y memcpy() .

Las dos estructuras son diferentes. Cuando inicializa la primera estructura, se asignan unos 40 bytes de memoria. Cuando inicializa la segunda estructura, se asignan aproximadamente 10 bytes de memoria. (La cantidad real depende de la architecture)

Puede usar los literales de cadena (constantes de cadena) para inicializar matrices de caracteres. Esta es la razón por

persona p = {“John”, “Doe”, 30};

funciona en el primer ejemplo.

No puede asignar (en el sentido convencional) una cadena en C.

Los literales de cadena que tiene (“Juan”) se cargan en la memoria cuando se ejecuta el código. Cuando inicializa una matriz con uno de estos literales, la cadena se copia en una nueva ubicación de memoria. En su segundo ejemplo, simplemente está copiando el puntero a (ubicación de) el literal de la cadena. Haciendo algo como:

 char* string = "Hello"; *string = 'C' 

podría causar errores de comstackción o de tiempo de ejecución (no estoy seguro). Es una mala idea porque está modificando la cadena literal “Hola” que, por ejemplo, en un microcontrolador, podría ubicarse en la memoria de solo lectura.