Memory allocation with malloc()

Asked

Viewed 77 times

0

Doubt 1: The pont should reserve a memory block for 1 integer which was requested on malloc(), but he reserves 32 bytes or a memory block for 8 integers.
'Cause he does it?

Doubt 2: If I make one for going to the X positions it manages to 'invade' the positions of the block allocated by pont2?

#include <stdio.h>

#include <stdlib.h>

int main()
{

    int *pont1 = malloc(sizeof(int));

    int *pont2 = malloc(sizeof(int));

    printf("Valor de pont1 (endereco de memoria alocada por pont1) = %d\n", pont1);

    printf("Endereco de pont1 = %d\n", &pont1);

    printf("\nValor de pont2 (endereco de memoria alocada por pont2) = %d\n", pont2);

    printf("Endereco de pont2 = %d\n", &pont2);

    long int endMemoriaAlocadoPont1 = &*pont1;
    long int endMemoriaAlocadoPont2 = &*pont2;

    int numeroBytes = (int) (endMemoriaAlocadoPont2 - endMemoriaAlocadoPont1);

    printf("\nMemoria alocada de cada pont = %d bytes\n", numeroBytes); //printa 32 Bytes

    
/*1°duvida: Os 'pont' deveriam reservar um bloco de memoria para 1 inteiro q foi o q pedi no malloc,
mas ele reserva 32 bytes ou seja um bloco de memoria para 8 inteiros, Porque ele faz isso?*/

    for(int i=0; i< 8; i++){ //digitando os valores no bloco de *pont1

        printf("Digite um valor para pont1[%d] = ",i);

        scanf("%d", &pont1[i]);

        printf("endereco de memoria de pont1[%d] = %d\n",i , &pont1[i]);
    }

    for(int i=0; i< 8; i++){

        printf("%d  ", pont1[i]);//printando valores do bloco q foi alocado por *pont1
    }

    printf("\nbloco de memoria alocado por *pont1 vai de %d ate %d\n", &pont1[0], &pont1[7]);

    /*2° duvida: Se eu faco um for indo ate a X posicoes ele consegue 'invadir' as pocicoes do
    bloco alocado por pont2, segue abaixo:*/

    for(int i=0; i< 10; i++){ //indo ate a 9º posicao, 'invadindo' 2 posicoes do bloco alocado por *pont2

        printf("Digite um valor para pont1[%d] = ",i);
        scanf("%d", &pont1[i]);
    }

    printf("valor de pont2[0] = %d\n", pont2[0]);//vai printar o valor digitado em 'pont1[8] do for acima

    printf("valor de pont2[1] = %d\n", pont2[1]);//vai printar o valor digitado em 'pont1[9] do for acima

    return 0;

}

Below is the output of the program: resultado

2 answers

2

First: this account uses a wrong concept to see the allocated space, nothing prevents to allocate an object at a huge distance from another, so measuring the distance between them will not give, guaranteed, the allocated size. Even if this case worked, don’t trust this information.

Second: it does not allocate space for 8 integers, it allocates 32 bytes, the amount of integers that fit there depends on where it is running, do not use this measure that it is wrong, it may be that in this case it was so, but using this measure teaches wrong.

The way the allocation is done is an allocator implementation detail, you don’t need to know that in most situations. In some cases where you need to manage the memory in an extreme way then it can be useful to know and try to do something, and it will probably be using a more economical allocator, paying the price it has on it, everything is choice, is tradeoff.

It is common for dynamic memory allocation only to be made in minimum sizes so landlords are optimized for this. It has some advantages for the allocator to use certain strategies to have some gain.

Usually when you have to allocate less than 32 bytes the object shouldn’t even be dynamically allocated.

Do not rely on visible behaviors when programming, especially in C. To use something you have to read all the documentation, learn all the details and use as you learned, not with what you saw. Certain behaviors happen by coincidence.

So even if you allocated 32 bytes and the whole is 4 bytes in size, use 8 slots in a place that has been reserved only for an integer may or may not work, in which case it did, but if the compiler uses another allocator, if it compiles for another architecture, it no longer works. Codes need to always work (unless you have a very specific requirement, but that should already be a mistake too).

The second question actually explains it better. You can access the memory freely, there is no error, but possibly will give an unwanted result, and the worst that can happen is to give the expected result, because whoever believes in what he sees instead of reading the documentation will think it is right, but it just worked, it was like this:

Fiat 147 todo detonado andando pelas ruas

Pointers exist to access memory addresses, that’s it, don’t think it does anything else, don’t think it has anything to do with allocation, including because the only guaranteed allocation is 4 bytes (in this case, it could be 2 or 8 in others, or even another size in some weird architecture or some crazy technique). Use as you wish and get any results that are there or change where you want. If you do everything right the result will be what you expect, if you do not do it right you can give the expected result or not. If you do wrong and have external interaction can open a nice security hole.

  • In the second doubt it is as follows: The malloc in the *pont1 allocated 32bytes ie in that allocated block fits 8 integers, from pont1[0] to pont1[7]... However in the last FOR I type values up to position 9 position -> point 1[8] = 1111 and point 1[9] = 2222 and not 'error'. The block of *point 1 only goes up to position 7 q vi is that the values of point 1[8] and point 1[9] 'invades' the block allocated by *point 2 as seen I print the value of point 2[0] and point 2[1] and are 1111 and 2222 respectively.

1


This is the malloc prototype()

    void *malloc(size_t size);

And this is what the documentation in Portuguese says in Microsoft Docs about malloc():

size Bytes to allocate

And about the value returned

malloc returns a void pointer to the allocated space or NULL if not there is enough memory available. To return a pointer to a different type of void , use a type conversion at the value of return. The storage space pointed out by the returned value is guaranteed to be subtly aligned for storage of any object type with an alignment requirement equal to or less than fundamental alignment. (In Visual C++, the fundamental alignment is the alignment required for a double or 8 bytes. In the code you have as target 64-bit platforms, it is 16 bytes. ) Use _aligned_malloc to allocate storage to objects that have a requirement of major alignment - for example, the types of SSE __m128 and __M256 types declared using __declspec(align( n )) where n is greater than 8. If the size is 0, malloc will allocate a zero-length item in the heap and will return a valid pointer for this item. Always check the malloc return, even if the requested amount of memory is little. Commentary The malloc function allocates a block of hair memory less bytes of size . The block can be larger than the size in bytes due to the space required for alignment information and maintenance. malloc defines Errno as ENOMEM if a memory allocation fail or if the amount of requested memory exceeds _HEAP_MAXREQ. For information about this and other error codes, see Errno, _doserrno, _sys_errlist and _sys_nerr. The startup code uses malloc to allocate storage for _environ, envp variables and argv .

Of the manual POSIX.1-2017 about malloc() has that note:

The malloc() Function Shall allocate unused space for an Object Whose size in bytes is specified by size and Whose value is unspecified.

The order and contiguity of Storage allocated by successive calls to malloc() is unspecified. The Pointer returned if the allocation succeeds Shall be suitably Aligned so that it may be Assigned to a Pointer to any type of Object and then used to access such an Object in the space allocated (until the space is explicitly Freed or reallocated). Each such allocation Shall Yield a Pointer to an Object disjoint from any other Object. The Pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null Pointer Shall be returned. If the size of the space requested is 0, the behavior is implementation-defined: the value returned Shall be either a null Pointer or a Unique Pointer

The bold part is what matters in your case. In Portuguese:

The order and continuity of the space allocated by successive calls of malloc() is undefined.

This means that you cannot do accounts and draw conclusions about these addresses and differences, as you did in your program.

Back on the show

Over these lines

    long int endMemoriaAlocadoPont1 = &*pont1;
    long int endMemoriaAlocadoPont2 = &*pont2;

Use shorter names when testing something...

& is the opposite of *. So much so as writing

    long int endMemoriaAlocadoPont2 = &*pont2;
    endMemoriaAlocadoPont2 = &*&*&*&*&*&*pont2;
    endMemoriaAlocadoPont2 = pont2;

dúvida1: The Pont should reserve a memory block for 1 integer which was requested in malloc(), but it reserves 32 bytes or a memory block for 8 integers. 'Cause he does it?

No, the system doesn’t do that. The allocated value is what was passed as argument. It may not even have been allocated, but you haven’t tested after all.

doubt2: If I make a go to the X positions it manages to 'invade' the positions of the block allocated by pont2?

Yes. Within the space allocated to your data. If the amount pointed out is outside your space will cancel the program with the popular exception "Access Violation"

Example

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

int main(void)
{

    int* pont1 = malloc(sizeof(int));
    *pont1 = 4;
    printf("Endereco de pont1 = %p\n", &pont1);
    printf("pont1 aponta para = %p\n", pont1);
    printf("e o valor la = %d\n", *pont1);

    int* pont2 = malloc(sizeof(int));
    *pont2 = 64;
    printf("\nEndereco de pont2 = %p\n", &pont2);
    printf("pont2 aponta para = %p\n", pont2);
    printf("e o valor la = %d\n", *pont2);

    int* outro = malloc(sizeof(int));
    memcpy( outro, pont1, sizeof(pont1));
    printf("valor de '*outro' com o endereco copiado de pont1 = %d\n\n", *outro);

    outro  = 1024;
    //printf("valor de '*outro' com o endereco 1024 = %d\n\n", *outro);
    long int endMemoriaAlocadoPont1 = &*pont1;
    printf("Endereco 2: %p\n", endMemoriaAlocadoPont1);
    endMemoriaAlocadoPont1 = &*pont1;
    printf("Endereco 2: %p\n", endMemoriaAlocadoPont1);
    endMemoriaAlocadoPont1 = &*&*&*&*&*&*&*&*&*pont1;
    printf("Endereco 2: %p\n", endMemoriaAlocadoPont1);
    return 0;

}

It’s practically your show and show

Endereco de pont1 = 012FF85C
pont1 aponta para = 01626CD0
e o valor la = 4

Endereco de pont2 = 012FF850
pont2 aponta para = 01625870
e o valor la = 64
valor de '*outro' com o endereco copiado de pont1 = 4

Endereco 2: 01626CD0
Endereco 2: 01626CD0
Endereco 2: 01626CD0

Pay particular attention to these lines:

   int* outro = malloc(sizeof(int));
    memcpy( outro, pont1, sizeof(pont1));
    printf("valor de '*outro' com o endereco copiado de pont1 = %d\n\n", *outro);

    outro  = 1024;
    //printf("valor de '*outro' com o endereco 1024 = %d\n\n", *outro);

outro is a pointer to int and was allocated via malloc(). It is not healthy in general use but as an example can be used memcpy() and copy an address there to see what’s in the memory at that address.

And the show shows the value 4 as expected, since it is what has in *pont1.
But if you take the second comment printf() and try to see the value of the 1024 address...

inserir a descrição da imagem aqui

And 0x400 in the popular decimal is 1024...

Browser other questions tagged

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