Difference between char array and char pointer

Asked

Viewed 1,802 times

8

I created a small example code to try to understand the difference between array of char and pointer of char.

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

typedef struct Person
{
    char name[256];
    char *apelido;
} person;

void insere_person_name(person *p){
    printf("insira um nome: ");
    scanf(" %s", p->name);
}

void insere_person_apelido(person *p){
    printf("insira um apelido: ");
    scanf(" %s", p->apelido);
}

void string_person(person *p){
    printf("person{nome:%s, apelido:%s}\n", p->name, p->apelido);
}

int main()
{
    person p;
    //person p = {"Fulano", "Lano"};

    insere_person_name(&p);
    insere_person_apelido(&p);

    string_person(&p);

    return 0;
}

By running this code we realize that it will cause an error when running the method insere_person_apelido(), if we uncomment person p = {"Fulano", "Lano"}; and instead of commenting on the methods of entering the data we realize that it is receiving the information correctly.

Please would like explanations so that I can understand the differences and when to use one or the other and how to use them.

  • 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.

  • @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. ;)

2 answers

7


A array allocates memory in the place where it was declared. Then name occupies 256 bytes within the structure Person. Any object of the type person will occupy little more than this when allocated.

A pointer is only a pointer to a memory address. It occupies only 4 bytes (on 32-bit architectures) or 8 bytes (64-bit). That’s all that will occupy in the structure. Great, right? But where is the nickname really allocated? In this code goes "anywhere" that the code find.

A small change will solve the problem. Simply allocate the memory dynamically, then you will have a suitable location for the string be remembered:

void insere_person_apelido(person *p) {
    p->apelido = malloc(256);
    printf("insira um apelido: ");
    scanf(" %s", p->apelido);
}

Normally this would have to be done a little bit better. It would have to release the memory when p no longer serve. But in a simple example, this does not cause problems.

A pointer always has to point to a memory address. It can be to something statically allocated by code or dynamically by malloc(). I used the second, but in this simple example I could have used another array allocated in the stack and point to him.

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

In C it’s very easy to pick up memory junk if you’re not careful.

Remember that the size of the objects need to be known at runtime before allocating. Some need to be known already at compile time. There is no magic.

It is also important to note that the access rating to arrays in some cases it is confused with pointers, but it is clear that arrays are not pointers.

Did the original example of the question work? Yes. But it’s completely wrong. That’s why I talk the same way that experienced professionals and novices don’t usually listen, so most never become experienced, even with decades of programming: working is circumstantial, understanding what you’re doing and producing the right code is the only correct way to program.

Looking like it works is not enough. You have to be right.

So "good practices" are bad, believing that "testing" is the solution is bad too, finding that methodologies alone save, and just looking at the surface of things doesn’t get someone anywhere.

This question is a step in the right direction to understand the real working, which in C is even more important than other languages, since it lets you do "everything" and it is your problem to know if it is correct.

  • Well, this was just an example code made purposefully for this "error", because I really want to understand what is really happening and when I should use one or the other, but now generated a new doubt, because as you mentioned at the beginning, on account of "char name[256]" any struct type object will occupy little more than that in memory, right, it will be independent of how many characters I actually use? That is, will it be allocated even if it is in arm? And with respect to another variable, it will not occupy the same space when declaring "malloc(256)"?

  • 1

    Occupies the same space, the allocation is independent of what is actually used. And more if you need more, it will use, only it will soften the next limb (the pointer) and possibly melar other things in memory. It is the programmer’s problem to solve this. With the malloc() is the same thing. It will occupy as much as determined, not as effectively used. And it can burst equal allocation. The advantage is that it can determine the size of the allocation at the time of execution, the 256 Inés could be a variable and its value could be determined before allocating memory, making memory usage more flexible.

  • I think that now I have understood about their use, because I have in mind that in the background everything is pointer in C, I thank you for the explanation, it was of great help, although I have marked the one of danieltm64, because unfortunately I can only score 1, but both were important for my growth.

  • 1

    Okay. The only thing is that what he explained doesn’t apply to your question that uses a structure. It doesn’t work.

  • In this case, I’d like to understand what differentiates a variable into a struct, and out of it, because I thought they were the same.

  • 1

    In the struct You need to be of known size. In very specific circumstances it is possible to have a variation, but complicating creation, cannot be used universally and does not apply to your example.

  • Let me get this straight: struct when I define a value, in this case the char nome[256] it will already allocate the space previously, the same would happen in the case of char *apelido and subsequently apelido = malloc(256), that is, it leaves plastered in memory this space to be used, for this very reason I can not create dynamic values, except for the case of the pointer, because this will allocate later, is this?

  • 1

    Yes, this is the difference of array, it always allocates space. In the case of pointer, the programmer, has to do with malloc(), All this is in the answer. That’s it. Everything has to have the space set to allocate. Everything in the computer, no matter the technology, that is mathematics. What can you do to make some things define themselves in the moment.

Show 3 more comments

5

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.

  • 1

    Right, but considering that internally everything is pointer in C, how could I know when it is best to use a char pointer and make a memory allocation with malloc and when I know that creating an array of char is the most appropriate? Is there any "sign" for this issue or simply goes to the programmer’s liking?

  • I added an explanation to my answer, see if it clears your doubt.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.