When you declare an array of char
thus:
char name[256];
the program allocates 256 characters in the main memory. When you declare a pointer of char
thus:
char *apelido;
the program allocates enough to store an address (usually 4 or 8 bytes) in the main memory.
When you use name
in the scanf
, it is treated as pointer and the string read from the default input is stored in the memory that was allocated to name
. When you use apelido
in the scanf
, it is also treated as pointer and the string read from the standard input is stored in the memory region for which apelido
points out. If apelido
points to a memory region that has not yet been allocated when scanf
tries to write there, the program aborts. If apelido
points to a memory region that has been allocated appropriately (for example with malloc
) the program works normally.
You can change the function insere_person_apelido
to the following:
void insere_person_apelido(person *p){
printf("insira um apelido: ");
p->apelido = malloc(256);
scanf(" %s", p->apelido);
}
With the above code, every time the function runs, enough memory to hold 256 characters will be allocated and the pointer apelido
will point to this memory region, in which the scanf
can leave the read characters of the default entry. If apelido
already pointed to a previously allocated memory region, this old memory region will never be released and memory leakage will occur, so beware of malloc
. Another solution would be for you to create a function that initializes a structure person
, thus:
void inicializar_person(person *p){
p->apelido = malloc(256);
}
This function allocates enough space for 256 characters and makes the member apelido
of p
point to this new memory region. You have to remember to always call this function when you instantiate a person
. Example:
person p;
inicializar_person(&p);
Thus, every instance of the structure person
will begin in a state that the other functions dealing with person
may assume, and the function insere_person_apelido
can be written like this:
void insere_person_apelido(person *p){
printf("insira um apelido: ");
scanf(" %s", p->apelido);
}
The above function assumes that apelido
points to a properly allocated memory region, which is always the case if p
was initialized by the function inicializar_person
. If in the future you add another pointer in the structure person
, you can adjust the function inicializar_person
and so the other functions can assume that the new pointer can be used. As long as you only use instances of the structure person
through appropriate functions instead of modifying a person
directly, your program will work properly.
When you declare a variable in C without initializing it, its initial value can be any value. Example:
int x = 5; // variável inicializada
int y; // variável não inicializada
printf("x = %d\ny = %d", x, y);
A possible output example of this code is:
x = 5
y = 19765
That is, how y
has not been initialized, its initial value will be any junk that was in the memory position in which the y
was allocated when your program ran.
Soon, when you try to write in memory to where an uninitialized pointer points, you will most likely access memory that your program has not yet allocated properly. However, every string written literally in the source code (such as "Fulano" or "Lano" in your example) is stored in your program’s executable file, and when the program runs, that string is stored in a certain region in the main memory, just when you assign "Lano" to apelido
, this address is stored at apelido
and the program works normally. The problem with apelido
is when you try to access the memory where it points and it does not point to a valid memory region, which is never the case when it points to a string that was written literally in the source code.
Accretion:
Starting with the C99 standard (think of C99 as the "version" of the C language that was published in 1999) it is possible to declare an array with variable size without resorting to malloc
, thus:
#include <stdio.h>
int main()
{
int tamanho;
printf("Digite um tamanho: ");
scanf("%d", &tamanho);
char name[tamanho];
name[tamanho - 1] = 'x';
printf("%c", name[tamanho - 1]);
return 0;
}
This code produces the same output as the following:
#include <stdio.h>
int main()
{
int tamanho;
printf("Digite um tamanho: ");
scanf("%d", &tamanho);
char *name = malloc(tamanho);
name[tamanho - 1] = 'x';
printf("%c", name[tamanho - 1]);
free(name);
return 0;
}
Before the C99 standard, it was not possible to declare an array with a known size only at runtime in the traditional way, so it was necessary to declare a normal pointer and use the function malloc
to allocate the array. However, from C99, it is possible to do this, but not in structures. In your case, you have a structure that needs to keep a nickname, and since not every nickname occupies the same size, I suggest you choose to use a normal pointer and call malloc
to allocate this array. If you accept that none of the nicknames in your program will take more than I don’t know 20 characters, you can declare the member apelido
thus:
char apelido[21];
So your code always spends 21 bytes for each nickname, but since no nickname has more than 20 characters, your program will not fail. The problem is to ensure this (if you can, beauty), and there is also the fact that a short nickname, for example 10 characters, will waste space (50% in this case), so I suggest stating apelido
so (and allocate it with malloc
):
char *apelido;
My advice is this: if you don’t know how much space you will need for all nicknames (or whatever the member of your structure is), use a common pointer and allocate the array with malloc
. If all nicknames (or any member of your structure) are the same size, or if you accept a possible waste of space, state the array in the traditional way, with a fixed size. Now, if you want all instances of your structure to point to the same nickname, without duplicating the content of the nickname in all instances of the structure, I also suggest that you use a simple pointer and allot the array with malloc
. If you want an array whose size will only be known at runtime and you need that array directly within a function (and not within a structure like the code you provided) and you have a compiler that supports C99, then you can simply declare the array like this:
tipo nome[tamanho];
where tamanho
can be a constant or the value of a variable.
Just to clarify: The negative vote on that other question you deleted was not mine. I did not vote against or in favour. I had even tried to come up with an answer the day you posted it, but I hadn’t been able to come up with anything.
– Victor Stafusa
@Victorstafusa, I know it was not yours, because you had commented well before, rest assured, I deleted because no one had presented a solution and I ended up doing the treatment by the front even, I do not know if it was the best way, but it was the one I found, so I thought it was unnecessary to keep the question. But be still all right. ;)
– bruno101