2009-08-18 12 views
28

Intenté averiguar qué estructura realmente es 'y' un problema, así que tengo realmente 2 preguntas:¿Arreglo de caracteres en una estructura incompatible?

1) ¿Qué se guarda en 'sara'? ¿Es un puntero al primer elemento de la estructura?

2) La pregunta más interesante: ¿Por qué no se compila? CCG dice "test.c: 10: error: tipos incompatibles en la asignación" y no puedo entender por qué ...

#include <stdio.h> 

struct name { 
    char first[20]; 
    char last[20]; 
}; 

int main() { 
    struct name sara; 
    sara.first = "Sara"; 
    sara.last = "Black"; 
    printf("struct direct: %x\n",sara); 

    printf("struct deref: %x\t%s\n", *sara, *sara); 


} 

(Esta parte ha sido resuelto por sus respuestas ya, genial!) ¡Gracias por tu ayuda!

+0

Aquí es en realidad una víctima completo: http://stackoverflow.com/questions/1265117/structure-problem-in-c/ – sharptooth

+1

awww. Pero sí busqué, realmente: D – Patrick

Respuesta

51

Esto no tiene nada que ver con estructuras - matrices en C no son asignables:

char a[20]; 
a = "foo"; // error 

es necesario utilizar strcpy:

strcpy(a, "foo"); 

o en su código:

strcpy(sara.first, "Sara"); 
+4

+1 Para 'strcpy' sobre' strncpy' ... :) – GManNickG

+0

Hubiera usado char * primero; sara.first = "Sara", ya que utilicé arreglos de tamaño fijo solo cuando realmente se requiere; ¿Es una buena o mala práctica (en C, no en C++)? – gramm

+1

@gramm Si lo hace, se compromete con la gestión de memoria dinámica, que puede no ser necesaria o conveniente. –

4

use strncpy para asegurarse de que no tiene desbordamiento de búfer.

char name[]= "whatever_you_want"; 
strncpy(sara.first, name, sizeof(sara.first)-1); 
sara.first[sizeof(sara.first)-1] = 0; 
+1

Esto supone que el truncado silencioso de los datos no hace que su programa falle en otro lugar más adelante. Por lo general, es mejor manejar explícitamente el caso donde la cadena no cabe en el búfer, que invocar un comportamiento no definido con strcpy o poner el programa en un estado inesperado con strncpy. Pero generalizo: si el resto de su programa representa el truncamiento silencioso (por ejemplo, nunca espera que sara.first coincida con "whatever_you_want"), entonces el estado del programa no es inesperado. –

+1

@onebyone este comportamiento debe estar documentado en el contrato. – TimW

+0

Si eso es suficiente, ¿por qué no solo documentar que la cadena de entrada no debe ser más larga de lo que la estructura puede soportar? El problema es diseñar API que ayuden a los clientes a evitar errores. IMO, ignorando silenciosamente lo que probablemente sea un error, no hace esto. Pero como digo, estoy generalizando, y puede que no sea un error. Si la función se llama "StoreFirst20CharsOf", entonces podemos suponer razonablemente que cualquier persona que eche un vistazo al código de llamada entenderá lo que hace. Entonces hay algunos usos para strncpy. –

2

sara es el struct sí mismo, no un puntero (es decir, la ubicación que representa la variable en la pila donde datos struct reales se almacena). Por lo tanto, *sara no tiene sentido y no se compilará.

+0

ah, ok ... Gracias – Patrick

0

La estructura de Sara es un bloque de memoria que contiene las variables internas. Casi no hay diferencia entre unas declaraciones clásicas:

char first[20]; 
int age; 

y una estructura:

struct Person{ 
char first[20]; 
int age; 
}; 

En ambos casos, se acaba de asignar parte de memoria para almacenar variables, y en ambos casos habrá 20 +4 bytes reservados. En su caso, Sara es solo un bloque de memoria de 2x20 bytes.

La única diferencia es que con una estructura, la memoria se asigna como un solo bloque, por lo que si toma la dirección inicial de Sara y salta 20 bytes, encontrará la "última" variable. Esto puede ser útil a veces.

cheque http://publications.gbdirect.co.uk/c_book/chapter6/structures.html para más :).

+0

Sara es un bloque de memoria de * al menos * 2 * 20 bytes.Puede ser más, si hay relleno. – caf

+0

Y 'offsetof (struct name, last)' tampoco es necesariamente 20 (aunque seguramente lo sea). – caf

+0

No sabía eso. ¿Existe una posibilidad de relleno al especificar el tamaño de la variable? Por ejemplo, velocidad de signo sin signo: 7; flags de char sin signo: 3; etc ... Estoy usando esto en el trabajo y nunca tuve un problema con el relleno y la alineación de datos. – gramm

3

También puede inicializar así:

struct name sara = { "Sara", "Black" }; 

Puesto que (como un caso especial) se le permite inicializar arrays de char de las constantes de cadena.

Ahora, en cuanto a lo que realmente es una estructura, es un tipo compuesto compuesto de otros valores. Lo que sara realmente parece en la memoria es un bloque de 20 valores de char consecutivos (que se puede consultar utilizando sara.first, seguido de 0 o más bytes de relleno, seguidos de otro bloque de 20 valores de char consecutivos (que se puede consultar utilizando sara.last) .Todas las demás instancias del tipo struct name se presentan de la misma manera.

En este caso, es muy poco probable que exista ningún relleno, por lo que un struct name es sólo un bloque de 40 caracteres, para los que tiene un nombre para el primer y el último 20 20.

Puede Averigüe qué tan grande es un bloque de memoria struct name usando sizeof(struct name), y puede averiguar en qué parte de ese bloque de memoria se encuentra cada miembro de la estructura usando offsetof(struct name, first) y offsetof(struct name, last).

8

O usted podría utilizar la asignación dinámica, por ejemplo .:

struct name { 
    char *first; 
    char *last; 
}; 

struct name sara; 
sara.first = "Sara"; 
sara.last = "Black"; 
printf("first: %s, last: %s\n", sara.first, sara.last); 
0

Puede usar strcpy para poblarlo. También puede inicializarlo desde otra estructura.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

struct name { 
    char first[20]; 
    char last[20]; 
}; 

int main() { 
    struct name sara; 
    struct name other; 

    strcpy(sara.first,"Sara"); 
    strcpy(sara.last, "Black"); 

    other = sara; 

    printf("struct: %s\t%s\n", sara.first, sara.last); 
    printf("other struct: %s\t%s\n", other.first, other.last); 

} 
Cuestiones relacionadas