
Gianluca Bargelli
Estoy tratando de entender cómo resolver este problema trivial en C, de la manera más limpia/segura. Aquí está mi ejemplo:
#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;
}
El error del compilador es:
main.c: En la función ‘main’: main.c:18: error: tipos incompatibles al asignar al tipo ‘char[20]’ del tipo ‘char *’
Entiendo que C (no C++) no tiene un tipo String y en su lugar usa matrices de char
s, por lo que otra forma de hacer esto fue alterar la estructura de ejemplo para contener punteros de 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;
}
Esto funciona como se esperaba, pero me pregunto si hay una mejor manera de hacerlo.

Péter Török
El primer ejemplo no funciona porque no puede asignar valores a las matrices: las matrices funcionan (más o menos) como punteros constantes a este respecto. Sin embargo, lo que puede hacer es copiar un nuevo valor en la matriz:
strcpy(p.name, "Jane");
Las matrices de caracteres 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 cabe en 19 caracteres (no 20 porque siempre se necesita un carácter para almacenar el cero final valor).
Por el contrario, los punteros son mejores si no conoce el tamaño máximo posible de su cadena y/o si desea optimizar el uso de la memoria, por ejemplo, evite reservar 512 caracteres para el nombre “John”. Sin embargo, con los punteros, debe asignar dinámicamente el búfer al que apuntan y liberarlo cuando ya no se necesite, para evitar pérdidas de memoria.
Actualizar: 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 las cadenas como objetos abstractos y en las matrices de caracteres como contenedores. La cadena puede tener cualquier tamaño, pero el contenedor debe tener al menos 1 más que la longitud de la cadena (para contener el terminador nulo).
C tiene muy poco soporte sintáctico para cadenas. No hay operadores de cadenas (solo operadores char-array y char-pointer). No puede asignar cadenas.
Pero puede llamar a funciones para ayudar a lograr lo que desea.
Él strncpy()
La función podría usarse aquí. Para máxima 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 la strncat()
y memcpy()
funciones
Las dos estructuras son diferentes. Cuando inicializa la primera estructura, se asignan alrededor de 40 bytes de memoria. Cuando inicializa la segunda estructura, se asignan unos 10 bytes de memoria. (La cantidad real depende de la arquitectura)
Puede usar los literales de cadena (constantes de cadena) para inicializar matrices de caracteres. Esta es la razón por
persona p = {“Juan”, “Doe”,30};
funciona en el primer ejemplo.
No puede asignar (en el sentido convencional) una cadena en C.
Los literales de cadena que tiene (“John”) se cargan en la memoria cuando se ejecuta su 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 cadena. Haciendo algo como:
char* string = "Hello";
*string = 'C'
podría causar errores de compilación o 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.