2009-08-08 12 views
8

Soy un novato total en C, vengo de C#. He estado aprendiendo sobre la administración de la memoria y la función malloc(). También he encontré con este código:¿Cómo se sabe cuánto espacio asignar con malloc()?

char *a_persons_name = malloc(sizeof(char) + 2); 

Lo que no entiendo es la cantidad de espacio esta es la asignación de a_persons_name. ¿Está asignando 2 caracteres (por ejemplo, AB) o algo más?

También sé que a veces puede ser "afortunado" con malloc y usar espacio no asignado (lo que puede provocar daños en los datos y seg). Entonces, ¿cómo sé cuánto espacio estoy asignando y cuánto necesitaré?

Respuesta

14

Ese fragmento está asignando espacio suficiente para un nombre de 2 caracteres.

En general, el búfer de cadena se va a llenar desde algún lugar, es decir, E/S. Si el tamaño de la cadena no se conoce de antemano (por ejemplo, al leer el archivo o el teclado), uno de los tres enfoques se utilizan generalmente:

  • definir un tamaño máximo para cualquier cadena dada, asignar ese tamaño + 1 (para el terminador nulo), lee a lo más que muchos caracteres, y error o trunca ciegamente si se suministraron demasiados caracteres. No terriblemente fácil de usar.

  • Realice la reasignación por etapas (preferiblemente utilizando series geométricas, por ejemplo duplicando, para evitar el comportamiento cuadrático), y continúe leyendo hasta que se llegue al final. No es terriblemente fácil de codificar.

  • Asigne un tamaño fijo y espere que no se exceda, y cuelgue (o sea propiedad) horriblemente cuando esta suposición falla. Fácil de codificar, fácil de romper. Por ejemplo, vea gets en la biblioteca C estándar. (Nunca utilice esta función.)

+2

¿Por qué todas las formas de asignar espacio suficiente aspiran? ¡NO HAY FORMA FÁCIL! – Kredns

+4

Las cadenas son la parte más fragmentada de C. Recomiendo codificar una estructura de pseudo-OO 'StringBuilder' o similar, y crear p. StrBufPrintf, StrBufGets, StrBufScanf, etc. para centralizar este tipo de operaciones. La biblioteca C estándar no ayuda mucho. C++ es un poco mejor, porque generalmente tiene 10 de diferentes clases de cadenas para elegir, una para cada marco distinto que se utiliza. Sí, estoy siendo sarcástico. –

+2

La manera fácil es usar (1) un idioma donde una cadena es un tipo básico; (2) use una biblioteca que proporciona un comportamiento de cadena; o (3) aprende el idioma que estás usando. Si no quiere aprender a usar las herramientas, ¿por qué lo intenta? Encuentre otro idioma que sea más adecuado para usted (no estoy tratando de insultar aquí, solo pragmático). – paxdiablo

1

Su llamada al malloc asignará 3 bytes de memoria. sizeof(char) es 1 byte y 2 bytes están indicados explícitamente. Esto le da suficiente espacio para una cadena de tamaño 2 (junto con el carácter de terminación)

5

Bueno, para empezar, sizeof(char) es siempre 1, por lo que podría simplemente malloc(3).

Lo que está asignando hay suficiente espacio para tres caracteres. Pero tenga en cuenta que necesita uno para un terminador nulo para cadenas C.

Lo que tienden a encontrar es cosas como:

#define NAME_SZ 30 
: : : 
char *name = malloc (NAME_SZ+1); 

de obtener suficiente almacenamiento para un nombre y un terminador de caracteres (teniendo en cuenta que la cadena "XYZZY" se almacena en la memoria como:

+---+---+---+---+---+----+ 
| x | y | z | z | y | \0 | 
+---+---+---+---+---+----+ 

veces con matrices no basados ​​en carbón, verá:

int *intArray = malloc (sizeof (int) * 22); 

que destinará espacio suficiente para 22 enteros.

+0

(tipo y conveniencia) 'int * intArray = malloc (sizeof (* intArray) * 22);' – u0b34a0f6ae

+0

"Bueno, para empezar, sizeof (char) siempre es 1" FALSE. C especifica 1 byte como LÍMITES INFERIORES para el tamaño de un carácter. El tamaño real depende tanto de la arquitectura como del compilador. En algunas construcciones más oscuras, un char es de 16 bits. –

+3

No, en realidad, sizeof (char) es * siempre * 1. De c1x, "6.5.3.4 El operador sizeof", párrafo 3: cuando se aplica a un operando que tiene tipo char, char sin signo o char firmado (o un versión calificada de la misma) el resultado es 1. – paxdiablo

1

Esto asignará tres bytes; 1 para sizeof (char), más dos.Al ver esa línea fuera de contexto, no tengo forma de saber por qué se asignaría de esa manera o si es correcta (me parece sospechosa).

Debe asignar suficiente memoria para guardar lo que necesite poner en ella. Por ejemplo, si está asignando memoria para contener una cadena, necesita asignar suficiente memoria para contener la cadena más larga esperada más un byte para la terminación nula. Si se trata de cadenas ASCII, es fácil: un byte por personaje más uno. Si está usando cadenas Unicode, las cosas se vuelven más complicadas.

3

malloc() asignará un bloque de memoria y devolverá un puntero a esa memoria si tiene éxito, y NULL si no tiene éxito. el tamaño del bloque de memoria se especifica mediante el argumento malloc, en bytes. El operador sizeof da el tamaño de su argumento en bytes.

char *someString = malloc(sizeof(char) * 50) 

esto va a asignar suficiente espacio para una cadena de 49 caracteres (una cadena de estilo C debe terminarse con un valor NULL ('\0') caracteres) sin incluir el carácter nulo, y el punto someString en esa memoria.

Parece que el código en su pregunta debe ser malloc(sizeof(char) * 2);, ya que sizeof(char) + 2 no tiene sentido.

tenga en cuenta que sizeof(char) es siempre igual a 1 (byte) - pero la representación de memoria de otros tipos (como long) puede variar entre los compiladores.

La forma en que obtiene (no) la suerte con la memoria asignada dinámicamente es si intenta leer/escribir fuera de la memoria que ha asignado.

Por ejemplo,

char *someString = malloc(10); 
strcpy(someString, "Hello there, world!"); 
printf("%s\n", someString); 

La primera línea asigna suficiente espacio para 9 caracteres y un carácter nulo.
La segunda línea intenta copiar 20 caracteres (19 + NULO) en ese espacio de memoria. Esto sobrepasa el búfer y puede causar algo increíblemente ingenioso, como sobrescribir la memoria adyacente o causar una segfault.

La tercera línea podría funcionar, por ejemplo, si había memoria asignada justo al lado de someString, y "¡Hola, mundo!" topado con ese espacio de memoria, podría imprimir su cadena más lo que haya en el siguiente espacio de memoria. Si ese segundo espacio terminara NULL, se detendría, a menos que no lo fuera, en cuyo caso se desviaría y eventualmente segfault.

Este ejemplo es una operación bastante simple, pero es tan fácil equivocarse. C es complicado, ten cuidado.

1

Primer punto: es un buen hábito nunca poner números absolutos en el argumento de malloc, siempre use sizeof y un múltiplo. Como se dijo anteriormente, la memoria asignada para algunos tipos varía con el compilador y la plataforma. Con el fin de garantizar poniendo suficiente espacio para una matriz de tipo 'burbuja' lo mejor es usar algo como esto:

blob *p_data = malloc(sizeof(blob) * length_of_array); 

De esta manera, cualquiera que sea el tipo es, sin embargo se ve en la memoria que obtendrá exactamente el cantidad correcta.

En segundo lugar, segfaults etc. C, como un lenguaje de bajo nivel, no tiene límites de comprobación. Esto significa que no hay nada que verificar que está mirando un índice que no está realmente en la matriz.De hecho, no le impide acceder a la memoria en cualquier lugar, incluso si no pertenece a su programa (aunque su sistema operativo podría, eso es lo que es una segfault). Esta es la razón por la cual, cada vez que pasas una matriz en C, necesitas pasar su longitud también, de modo que la función que recibe la matriz sabe cuán grande es. No olvide que una 'matriz' es en realidad solo un puntero al primer elemento. Esto es muy inútil al pasar cadenas: cada argumento de cadena se convertiría en dos argumentos, por lo que se usa un truco. Cualquier cadena C estándar tiene terminación NULL. El último carácter de la cadena debe tener el valor ASCII 0. Cualquier función de cadena funciona a lo largo de la matriz hasta que la vea y luego se detenga. De esta forma, no invaden la matriz, pero si no existe por alguna razón, lo harán. Eso ser comprendido

strlen("Hello") 

es 5, pero para almacenarlo necesita un personaje más. Ej .:

const char str1 = "Hello"; 
char *str2 = malloc(sizeof(char) * (strlen(str1) + 1)); 
strcpy(str2, str1); 

Y sí, sizeof (char) es innecesaria, ya que se define como 1, pero me resulta más clara y definitivamente es un buen hábito.

+0

1) No estoy de acuerdo con "mejor usar algo como esto:" 'p_data = malloc (sizeof (blob) * length_of_array);' 'p_data = malloc (sizeof * p_data * length_of_array);' ya que no depende de la codificación del tipo correcto y manteniéndolo correcto a medida que cambia el código. 2) Ejemplo de uso: 'str2 = malloc (sizeof * str2 * (strlen (str1) + 1));' – chux

Cuestiones relacionadas