1

I am trying to malloc a 1 d array of pointers following a 1d array of struct type entry.

While making each pointer points to the correspondent element of the 1d array, I hit the problem.

The pointers stores at the beginning of the memory and each pointer points to the address of each entry.

Below is a simple illustration:

--------------------------
ptr1|ptr2|ptr3|ptr4|ptr5
--------------------------
entry1
--------------------------
entry2
--------------------------
entry3
--------------------------
entry4
--------------------------
entry5
--------------------------


each pointer in the array of pointers points to entry 1- 5 accordingly.

Here is the code,

#include <stdio.h>

#define MAX_LAST_NAME_SIZE 16
#define TABLE_SIZE 131072  //2^17

typedef struct __PHONE_BOOK_DETAIL {   //not really matter in this question
    char firstName[16];
    char city[16];
    char zip[5];

} __PHONE_BOOK_DETAIL;

typedef struct __PHONE_BOOK_ENTRY {    // the size is 16 + 8 +8 =32byte
    char lastName[MAX_LAST_NAME_SIZE];

    __PHONE_BOOK_DETAIL *detail;

    struct __PHONE_BOOK_ENTRY *pNext;

} entry;

int main()
{
    int i;

    entry  **pHead;
    entry  *e; 
    pHead = (entry **) malloc(sizeof(entry *)*TABLE_SIZE + sizeof(entry)* TABLE_SIZE);

    for(i=0;i<TABLE_SIZE;i++){
        pHead[i]=  (pHead+ TABLE_SIZE) + sizeof(entry)*i;
        printf("i=%d , phead[i]=%p &phead[i]=%p, sizeof (entry)=%d sizeof(e)=%d \n",i, pHead[i],&pHead[i],sizeof(entry),sizeof(e));
        //pHead[i]->pNext=NULL;
    }
    return 0;
}

output:

i=0 , phead[i]=6b597010 &phead[i]=6b497010, sizeof (entry)=32 sizeof(e)=8
i=1 , phead[i]=6b597110 &phead[i]=6b497018, sizeof (entry)=32 sizeof(e)=8
i=2 , phead[i]=6b597210 &phead[i]=6b497020, sizeof (entry)=32 sizeof(e)=8
i=3 , phead[i]=6b597310 &phead[i]=6b497028, sizeof (entry)=32 sizeof(e)=8
i=4 , phead[i]=6b597410 &phead[i]=6b497030, sizeof (entry)=32 sizeof(e)=8
i=5 , phead[i]=6b597510 &phead[i]=6b497038, sizeof (entry)=32 sizeof(e)=8
i=6 , phead[i]=6b597610 &phead[i]=6b497040, sizeof (entry)=32 sizeof(e)=8
i=7 , phead[i]=6b597710 &phead[i]=6b497048, sizeof (entry)=32 sizeof(e)=8
i=8 , phead[i]=6b597810 &phead[i]=6b497050, sizeof (entry)=32 sizeof(e)=8
i=9 , phead[i]=6b597910 &phead[i]=6b497058, sizeof (entry)=32 sizeof(e)=8
                      ....

The program crashes when i = 16369. It seems to be memory access violation.

My CPU is 64 bit, so the pointer size is 8 bytes.

However, while I am expecting the size of entry is 32byte, you can see the increment of phead[i] is 256. Can anyone explain that?

Thanks!

14
  • 3
    Your malloc code is nonsense. You probably want a 2D array instead. See Correctly allocating multi-dimensional arrays. Commented Apr 12, 2018 at 9:03
  • 1
    Hint: 32*8==256. Commented Apr 12, 2018 at 9:23
  • 2
    This is very dirty code, relying on sensible alignment, but you can set e = (entry*)(pHead + TABLE_SIZE); followed by pHead[i] = &e[i];. Commented Apr 12, 2018 at 9:25
  • 2
    The original code had problems with pointer arithmetic. Remember that addition of an integer to a pointer is scaled by the size of the dereferrenced pointer type. Commented Apr 12, 2018 at 9:35
  • 3
    You are mixing size/offset in elements with size/offset in bytes. You need to read the chapter about pointer arithmetic again. Commented Apr 12, 2018 at 9:40

1 Answer 1

2

I am expecting the size of entry is 32byte, you can see the increment of phead[i] is 256.
Can anyone explain that?

Unexpected bad pointer math.

//                                 + this adds by the size of *pHead 
// pHead[i] = (pHead + TABLE_SIZE) + (sizeof(entry) * i);

With compiler warnings fully enabled, OP may have received the below, hinting at the problem.

warning: assignment from incompatible pointer type [-Wincompatible-pointer-types] 

Tip: Save time, enable all compiler warnings.


There is also an alignment/size problem in that the 2nd half entry[] array may not align as needed. @Ian Abbott

A simple approach to avoid issues is to create a struct of the desired memory and allocate to that.

int main(void) {
  //  This is the memory layout that OP seeks
  typedef struct {
    entry *pHead[TABLE_SIZE];
    // Compiler will determine if padding needed between the 2 members.
    // OP's code reasonably assumed zero padding - yet best not to assume it.
    entry e[TABLE_SIZE];
  } all;

  all *a = malloc(sizeof *a);  // Simple!
  if (a == NULL) {
    return (EXIT_FAILURE);
  }

  entry **pHead = a->pHead;
  entry *e = a->e;

  for (size_t i = 0; i < TABLE_SIZE; i++) {
    pHead[i] = &e[i];
    printf(   // format corrected
        "i=%zu, phead[i]=%p &phead[i]=%p, sizeof (entry)=%zu sizeof(e)=%zu \n",
        i, (void *) pHead[i], (void *) &pHead[i], sizeof entry, sizeof e);
  }
  free(pHead); // Note pHead and `a` point to the same memory.
}

Output

i=0, phead[i]=0x600061fc8 &phead[i]=0x600061f90, sizeof (entry)=32 sizeof(e)=8 
i=1, phead[i]=0x600061fe8 &phead[i]=0x600061f98, sizeof (entry)=32 sizeof(e)=8 
i=2, phead[i]=0x600062008 &phead[i]=0x600061fa0, sizeof (entry)=32 sizeof(e)=8
...
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for that! this post answers my question why the increment is 200 byte. Although I understand how to code it correctly after reading previous comments, I am still thinking why the wrong code behaves like this. This post is simple and clear!
@CraigYang (pHead + TABLE_SIZE) + (sizeof(entry) * i) --> is like ((char *)pHead + sizeof(*pHead)*TABLE_SIZE) + (sizeof(*pHead)*sizeof(entry) * i) - that is pointer math.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.