0

I get null memory using following code of malloc/calloc. Sometimes it fails to allocate memory for "name1" and then strcpy fails. Please guide.

struct testMalloc
{
    char name1[90];
    char name2[90]; 
    struct testMalloc* ptr;
};
int main(int argc, char* argv[])
{
    struct testMalloc* test = 0 ;   
    int size = 0;
    size = sizeof(struct testMalloc);

    printf("Size of struct is %d", size);

    test = (struct testMalloc*) calloc(sizeof(struct testMalloc));  
    
    strcpy((test->name1), "hdshdssdsdfsfffffffffffffffffffffffffffffh");

    return 0;

}
alinsoar
  • 15,386
  • 4
  • 57
  • 74
  • A pointer cannot be initialized with 0 but with `(void*)0` in case you want to get a NULL pointer as value. Otherwise it is undefined behavior. – alinsoar Aug 06 '20 at 13:47
  • @alinsoar Are you sure? Do you have a source? – klutt Aug 06 '20 at 13:48
  • @alinsoar The C standards committee did, in fact, finally surrender to all those misguided programmers who believed that `0` ***IS*** `NULL`. It's not actually `NULL` now, but `0` is a null-pointer constant per the C standard. – Andrew Henle Aug 06 '20 at 13:51
  • @AndrewHenle On some systems I heard the null pointer does not have all bits 0, but have never seen such a system. – alinsoar Aug 06 '20 at 13:53
  • @alinsoar `0` when converted to a pointer type is always `== NULL`. It does not have to be represented by all bits 0. It does not matter whether you put an explicit cast `(void *)` or merely allow it to be converted implicitly. – trent Aug 06 '20 at 13:56
  • @alinsoar What trentcl said. `NULL == 0` is guaranteed to evaluate to true. – klutt Aug 06 '20 at 13:59
  • @alinsoar Such systems do exist. But C also has the concept of a "null pointer constant", of which `NULL` is one. `NULL` does not have to be zero, but the numeric value of `0` is defined to be a "null pointer constant". And all null pointers are defined to be equal. It's basically a standards-hack to allow what would otherwise be bad code that assumes `NULL` is in fact `0` to work. – Andrew Henle Aug 06 '20 at 14:00
  • Probably to compare with NULL would be interpreted something like `define NULL? (x) x – alinsoar Aug 06 '20 at 14:03
  • @alinsoar No, comparing pointers with numbers is not legal C *unless* the number is exactly `0`. Converting an integer to a pointer is not guaranteed to render a pointer with the same bit representation as the integer. If on a particular architecture `NULL` is the pointer value 0x8675309, then `(void *)0` is represented in the machine by 0x8675309. But within your C code it's still a null pointer. – trent Aug 06 '20 at 14:07
  • See [C FAQ 5.5](http://c-faq.com/null/machnon0.html), [5.9](http://c-faq.com/null/nullor0.html), and [5.10](http://c-faq.com/null/macsochange.html) for some further explanation. The reason to use `NULL` instead of `0` is nothing to do with internal representations of null pointers. – trent Aug 06 '20 at 14:14

5 Answers5

7

You do not include <stdlib.h> for the compiler to know the signature of calloc and in this case it uses K&R calling convention.

If you include <stdlib.h> the code won't compile before to correctly call the calloc.

alinsoar
  • 15,386
  • 4
  • 57
  • 74
3

calloc takes 2 arguments: the number of elements, and the size of each element. It will zero out the allocated memory. What you're looking for is malloc, which only takes 1 argument: the total size of the allocated memory chunk, and it does not zero out the allocated memory.

Aplet123
  • 33,825
  • 1
  • 29
  • 55
2
  1. Always check the result of malloc.
  2. Use the objects instead of types in sizeof
  3. Try to use safer versions of string functions (in this example passed string is longer that the array.
  4. You do not have to cast result of the malloc and it is considered as bad practice (nowadays rather obsolete but anyway)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct testMalloc
{
    char name1[20];
    char name2[90]; 
    struct testMalloc* ptr;
};

struct testMalloc *allocAndCopy(const char *str)
{
    struct testMalloc *ptr = malloc(sizeof(*ptr));
    if(ptr)
    {
        strncpy(ptr -> name1, str, sizeof(ptr -> name1));
        ptr -> name1[sizeof(ptr -> name1) - 1] = 0;
    }
    return ptr;
}


int main(int argc, char* argv[])
{
    struct testMalloc* test = allocAndCopy("hdshdssdsdfsfffffffffffffffffffffffffffffh");

    if(test) printf("the string is: %s\n", test -> name1);
}

https://godbolt.org/z/zjvvYW

0___________
  • 60,014
  • 4
  • 34
  • 74
1

There are few syntax errors:

  1. struct testMalloc* test = NULL; This is how a NULL pointer is initialized
  2. calloc(sizeof(struct testMalloc)); too few arguments passed to calloc. The correct form is calloc(no_of_elements, sizeof(type));

Here is the correct implementation of your code:

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

struct testMalloc
{
    char name1[90];
    char name2[90]; 
    struct testMalloc* ptr;
};

int main(int argc, char* argv[])
{
    struct testMalloc* test = NULL;
    size_t size = sizeof(struct testMalloc);

    printf("Size of struct is %ld\n", size);

    if((test = (struct testMalloc*)calloc(1, size)) == NULL){
        return -1; //Failed to allocate memory
    }
    else {
        strcpy((test->name1),"hdshdssdsdfsfffffffffffffffffffffffffffffh");
        printf("%s\n",test->name1);
    }
    
    return 0;
}
Sourabh Choure
  • 723
  • 4
  • 15
  • I would 1. use `sizeof(*test)` instead which is more flexible, 2. never access `test` before testing that it's not `NULL`. It's a common mistake to assume that the allocation always succeeds, but it's not really the case. – Iharob Al Asimi Aug 06 '20 at 14:12
  • @IharobAlAsimi `malloc()` and `calloc()` uses `sbrk()` / `brk()` which can change the heap size. The problem mainly occurs when we use `mmap()` as there we allocate almost heap memory as large as a page. – Sourabh Choure Aug 06 '20 at 14:22
  • 1
    Stick to the manuals and to the standard definition. How `malloc()` is implemented is irrelevant. If it fails for any reason (which can be implementation specific) it will return `NULL`. NEVER ASSUME. – Iharob Al Asimi Aug 06 '20 at 16:25
  • Okay, I guess I might have learned something new @IharobAlAsimi from you to "never assume" when using functions whose failure can be inevitable. I will update the answer. – Sourabh Choure Aug 06 '20 at 16:36
  • 1
    It is not a matter of inevitable. It's Murphy's law! – Iharob Al Asimi Aug 06 '20 at 17:17
1

From top to bottom:

1.

You forgot to #include stdlib.h to use calloc() and malloc(). Implicit declarations are prohibited since C99.

2.

int main(int argc, char* argv[])

Your program does not need to get arguments into it.

This:

int main (void)

would be more appropriate.

3.

int size = 0;

size should never have a negative value. So it would be more appropriate to declare it as unsigned int or even better size_t.

4.

struct testMalloc* test = 0 ; 

You can use 0 to initialize a pointer. It's perfectlty valid as 0 is a null pointer constant. But better use NULL when dealing with pointers and not 0 to show the pointer intention and increase the readability.

struct testMalloc* test = NULL; 

5.

calloc(sizeof(struct testMalloc)); 

calloc requires two arguments in comparison to malloc. The first needs to be number of items and the second the size of one item.

calloc(sizeof(1,struct testMalloc)); 

6.

test = (struct testMalloc*) calloc(sizeof(struct testMalloc)); 

You do not need to cast the return value of malloc() or calloc().

7.

You forgot to check the returned pointed from calloc() for a null pointer if the allocation has failed. Always check the return value of memory-management functions.

test = calloc(1, sizeof(struct testMalloc)); 
if (test == NULL)
{
    fputs("Allocation failed!", stderr);
    // error routine.
}