简体   繁体   中英

How can malloc take more number of bytes of data than assigned

According to what I have understood about malloc() is it allows us to assign the memory dynamically during the runtime. Below is the code that I am looking into

#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main() {
  char *description;
  clrscr();
  description = malloc(2*sizeof(char));
  strcpy(description,"Hello there!");
  printf("%s",description);
  free(description);
  printf("%s",description);
  getch();
}

My question is I am asking system to assign 2 bytes of memory in the malloc() function. So when I try to fill the string "Hello there!" and print the same I should get only the first 2 characters of the string as output but I am getting the whole string that I have given in strcpy() function in the output.

And also after I use free() function if I try to print description again I should not get any output if I am not wrong but I am still getting the same string again. May in know how this works. I am using turbo C++ compiler.

The malloc() function allocates at least the amount of memory you request though it may be more. However the amount of memory that malloc() provides is not really the central issue here.

The C programming language is designed for speed and efficiency which means that many of the checks that other languages do are not done. So you can write a program that does something wrong and it will still work under some circumstances and in other circumstances not work.

In C a pointer is the address of a memory location. C does not check if the address is a valid address or not. C does not check that the amount of memory you are trying to use is the correct amount of memory.

So here is an annotated version of your program.

#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main() {
  char *description;   // create a variable that will contain the address of a character
  clrscr();
  // allocate an array of characters. the number of characters is 2 so this
  // will allocate a minimum size memory area that will hold 2 characters.
  // malloc() may round up the size or it may not but all you can count on
  // is 2 characters in size.
  description = malloc(2*sizeof(char));
  // copy a constant string to the memory location pointed to by the variable
  // description. the strcpy() function does not check on the limits of the
  // memory. after the malloc() is done there is no size information available
  // to strcpy() or any other of the C runtime library functions in the C Standard Library
  // this is copying 11 characters plus the end of string for a total of 12 characters
  // so to be correct the memory area pointed to by description should be at least
  // 12 characters however we know from the malloc() above it is guaranteed to
  // be only 2 characters so we are going past the memory area with this strcpy().
  strcpy(description,"Hello there!");
  // however we get lucky and it works anyway.
  printf("%s",description);
  // tell the memory allocation library that you are done with the memory and it
  // can be used for something else now. the pointer will probably still be good
  // for a while because the memory allocation, which gets its memory from the
  // operating system, does not normally give any freed memory back to the OS.
  // instead it normally just keeps it until the application terminates.
  // as long as this freed memory is not used for something else, more than
  // likely whatever you put there will remain there as is. however the moment
  // the memory is given to something else, the values will change.
  free(description);
  printf("%s",description);
  getch();
}

You can get an idea as to what is happening if you try the following sample program which is a modification of yours that instead of using malloc() uses variables on the stack.

#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main() {
    char array1[12] = { 0 };
    char array2[2] = { 0 };
    char array3[12] = { 0 };
    char *description;
    printf("Before\n  array1 %s\n", array1);
    printf("  array2 %s\n", array2);
    printf("  array3 %s\n", array3);

    description = &array2[0];
    strcpy(description, "Hello there!");
    printf("description %s\n", description);

    printf("\nAfter\n  array1 %s\n", array1);
    printf("  array2 %s\n", array2);
    printf("  array3 %s\n", array3);
}

Using Visual Studio 2013 and running in Debug mode I get a warning about memory being overwritten as the application terminates. When I do a release build and run it, there are no errors and I get the following output. As you can see the strcpy() function just copied the characters overwriting adjacent memory. It looks like the Visual Studio 2013 compiler is aligning memory on a double word boundary so that only the last few characters of the string are visible in the adjacent memory area. Visual Studio padded the variable array2[] so that the next variable allocated is on a double word boundary.

Before
  array1
  array2
  array3
description Hello there!

After
  array1
  array2 Hello there!
  array3 ere!

If we modify the above program to the following:

#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main() {
    char array1[12] = { 0 };
    char array2[2] = { 0 };
    char array3[12] = { 0 };
    char *description;
    int  *values;
    printf("Before\n  array1 %s\n", array1);
    printf("  array2 %s\n", array2);
    printf("  array3 %s\n", array3);

    description = &array2[0];
    strcpy(description, "Hello there!");
    printf("description %s\n", description);

    printf("\nAfter\n  array1 %s\n", array1);
    printf("  array2 %s\n", array2);
    printf("  array3 %s\n", array3);

    description = malloc(8 * sizeof(char));
    strcpy(description, "this");
    printf("\n\nMalloc\n  first description %p %s\n", description, description);
    free(description);

    values = malloc(1 * sizeof(int));
    *values = 0;
    printf("  pointer %p and value %d\n", values, *values);
    printf("  second description %p %s\n", description, description);

}

Then we get the following output. In this case we got lucky and were given the same memory area on the malloc() of the int so when we modified the int we also modified the area pointed to by description because once it was freed then malloc() reused the area for the next allocation.

Before
  array1
  array2
  array3
description Hello there!

After
  array1
  array2 Hello there!
  array3 ere!


Malloc
  first description 00944B28 this
  pointer 00944B28 and value 0
  second description 00944B28

The Resource Ownership Principle

This example demonstrates two rules when using malloc() and free() .

Allocate with malloc() the amount you need and never exceed the amount of memory you requested. If you need more then look at the realloc() function.

Once you free a memory area using free() never use that pointer value again. You no longer own the memory area once it is freed.

When you use malloc() you become the owner of the memory but only that memory that you requested. When you use free() you relinquish ownership of the memory and you should not use it any more because you no longer own it.

Malloc allocates 2 bytes. This means from a starting point (the one returned by the malloc) give me 2 bytes. strcpy copies all bytes in the string "hello there!" starting at the address in description. This does not care about the allocation, it just copies the bytes. The %s in printf tells printf to look for a null terminated string.

free() is used to tell the memory manager that the bytes can be used for other purposes again. It does not erase the data already present.

As @Michael Foukarakis pointed out, writing bytes in unallocated memory may cause undefined behavior. If something else were to write on the not allocated memory between the statements things will break.

if you put more data then merory size beaviour'll be umpredictable.

Nothing will warning you about your bad action but a memory fault can happen anytime.

description = malloc(2*sizeof(char));

You are requesting 2 bytes of storage. In case of success, that's all the memory description will point to that you can safely use.

strcpy(description,"Hello there!");

You are writing past the end of the memory allocated with malloc (proof: "Hello there!" has a length of more than 2), therefore your program invokes undefined behaviour.

printf("%s",description);
free(description);
printf("%s",description);

None of the above 3 lines have any meaning in a program which invokes undefined behaviour. Any expectations from them are baseless and wrong.

Additionally, attempting to print the string (assuming to be) pointed to by description after free(description); also invokes undefined behavior.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM