-1

today I encountered a problem with the dynamic creation of char arrays.
The following code is an example which causes the issues:

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

int main (void){

        char** top = NULL;
        top = malloc(30*sizeof(char));

        printf("sizeof top:%d\n",sizeof(top));

        for(int  i = 0; i < sizeof(top); i++){
                top[i] = malloc(12*sizeof(char));
                strcpy(top[i],"Lorem Ipsum");
        }


        for(int i = 0; i < sizeof(top); i++){
                printf("%d: %s\tsize: %d\n",i,top[i],strlen(top[i]));
        }
}

The expected output would look like this:

sizeof top:30
0: Lorem Ipsum  size: 11
1: Lorem Ipsum  size: 11
2: Lorem Ipsum  size: 11
3: Lorem Ipsum  size: 11
4: Lorem Ipsum  size: 11
5: Lorem Ipsum  size: 11
6: Lorem Ipsum  size: 11
7: Lorem Ipsum  size: 11

but instead I get this output:

sizeof top:8
0:      size: 0
1: Lorem Ipsum  size: 11
2: Lorem Ipsum  size: 11
3: Lorem Ipsum  size: 11
4: Lorem Ipsum  size: 11
5: Lorem Ipsum  size: 11
6: Lorem Ipsum  size: 11
7: Lorem Ipsum  size: 11

I already tried to change the size of all arrays but it keeps unchanged. I really don't understand why the size of top stays at 8 even i try to allocate more memory and why the first string stored to the arrays won't be shown correctly while the others do. After some research i couldn't find any information about similar problems. Someone could please explain this situation to me or recommend a reliable source?

Thanks in advance!

EDIT: I thought the issue had to do with the usage of the char** array (which it kind of did). I was unaware that the real issue was the value returned by sizeof. Thanks a lot for your kind answers and the quick aid.

L.Spillner
  • 1,772
  • 10
  • 19
  • 1
    You cannot get the size of allocated memory with `malloc`. You allocate `30*sizeof(char) (=30)` bytes. There is no way to "get back" `30`. – Jabberwocky Jun 26 '17 at 10:01
  • 1
    Size of doesn't do what you think it does. `sizeof` returns the size of a pointer not the pointed value. – user1937198 Jun 26 '17 at 10:02
  • BTW: you want `top = malloc(30*sizeof(char*));` instead of `top = malloc(30*sizeof(char));`. You want to allocate space for 30 _pointers_, not 30 _chars_. – Jabberwocky Jun 26 '17 at 10:03
  • 1
    It's best practice to follow a pattern of `pointer = malloc(count * sizeof *pointer)` rather than `pointer = malloc(count * sizeof (type))`, because the first form drastically reduces the likelihood of getting the type wrong, and it won't silently do the wrong thing if the type of `pointer` changes. – jamesdlin Jun 26 '17 at 10:08
  • Thank you all for this much help. The error with the first output confused me that much, that i wasn't aware of the usage of malloc(char*); Thanks alot. – L.Spillner Jun 26 '17 at 10:23

2 Answers2

0

This most likely won't result in what you (probably) intend:

char** top = malloc(30*sizeof(char));

top is itself is a pointer to char*, so it could point to either a char* itself or to an array of. So you actually would need:

char** top = malloc(30*sizeof(char*));
//                                ^

But as top is a pointer, sizeof(top) will give you the size of a pointer (any arbitrary one) on your system, most likely 8 (as on modern 64 bit hardware).

sizeof only works as intended if you apply it to arrays directly (without having e. g. passed them to a function, in which case they are passed as pointer only!):

int a[7];
size_t n0 = sizeof(a); // n == 7*sizeof(int)
// if you want the number of elements (which is what you normally do)
// (and you missed that above, too!):
size_t n1 = sizeof(a)/sizeof(*a);
// alternatively:
size_t n2 = sizeof(a)/sizeof(a[0]);

As you use pointers, you will have to keep your array length elsewhere:

for(int i = 0; i < 30; ++i)
//                 ^ instead of sizeof(top) - but bad, see below!

Well, sure, now you have magic numbers in the code, which is what you (correctly!) wanted to avoid...

Solution: use constants, either as const variable or as a define:

size_t const NumberOfElements = 30;
#define NUMBER_OF_ELEMENTS 30

If you want to be able to modify the length (e. g. via realloc), the define is out, and you need a non-const variable:

size_t NumberOfElements = 30;

If you don't use the entire array all the time, you might need two variables, I personally like using capacity and size (in the style of C++'s std::vector):

size_t capacity = 32; // initial capacity
size_t size     = 0;  // current size

Consider prefixes to avoid name collistions, if need be.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
0

sizeof(top) is evaluated in compile time.

malloc is executed in runtime.

Therefore, there's no way to receive the 30 bytes in runtime from sizeof(top).


  • VLA (variable length array), is an exception for that. In that case sizeof will be evaluated dynamically at runtime.

    int x;
    scanf("%d", &x);
    char ch[x];
    printf("%d\n", (int)sizeof ch);
    

    If 7 is read into x the sizeof of ch will be evaluated on runtime and will print 7.

SHG
  • 2,516
  • 1
  • 14
  • 20