0

Please consider this C code:

I've an array of a struct on the stack. This struct has 3 fixed-length array of characters. Since it's on stack, memory is all pre-allocated and I don't have to worry about c/malloc or freeing.

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

struct memberStruct {
    int Field1;
    char Name[128];
    char Token[128];
    char Secret[128];
    int Epoch;
    int Age;
    int Zip;
    int Devices;
    int Leaves;
};

struct memberStruct members[8192] = { 0 };

void printMember(struct memberStruct *member);

int main() {
    printf("size of members: %d\n", sizeof(members));
    printMember(&members[0]);
    struct memberStruct *ptr = &members[1];
    printf("member0 is at %p\n", ptr);
    memcpy(ptr->Name, "Member 1 Name", 32);
    printMember(ptr);
    printMember(&members[1]);
    return 0;
}

void printMember(struct memberStruct *member) {
    printf("This is member at %p\n", member);
    printf("member Name: %s, Age: %d, Zip: %d, Secret: %s\n", member->Name, member->Age, member->Zip, member->Secret);
}

I find this convenient. But when you run it,

$ ./question 
size of members: 3342336 // <-- THIS!
This is member at 0x21030
member Name: , Age: 0, Zip: 0, Secret: 
member0 is at 0x211c8
This is member at 0x211c8
member Name: Member 1 Name, Age: 0, Zip: 0, Secret: 
This is member at 0x211c8
member Name: Member 1 Name, Age: 0, Zip: 0, Secret: 

You can see it takes ~3.3MB of memory, a lot on the stack, which brings me to the question:

Is there a way I can create this array of struct on the heap (with mem set aside for the members with fixed-length array of chars)?

struggling_learner
  • 1,214
  • 15
  • 29
  • 1
    Static variables are not stored on the stack (only local are ex: your ptr variable). For more details you can read https://stackoverflow.com/questions/93039/where-are-static-variables-stored-in-c-and-c – Olivier Pellier-Cuit Dec 18 '20 at 01:30
  • @OlivierPellier-Cuit Since `members[8192] = { 0 }` is zero initialized, that link states it goes to `BSS`. Question, does it still count against my stack size of `ulimit -s` which is `8Meg`? Thanks! – struggling_learner Dec 18 '20 at 01:42
  • I don't think so but i am not completly sure (may be someone can confirm ?). You could try to create a very big one for testing. – Olivier Pellier-Cuit Dec 18 '20 at 01:54
  • thanks I tried with a large alloc, it did not die - also saw https://stackoverflow.com/a/12126321/9488865 - thank you @OlivierPellier-Cuit , I learned something new and useful! – struggling_learner Dec 18 '20 at 02:34
  • 1
    a few comments: 1) `sizeof()` returns a unsigned long value (I.E. a `size_t`) Print a `size_t` with `%zu` NOT `%d` 2) the `%p` is expecting a `void*` parameter, not a `struct member` type`. 3) regarding: `struct memberStruct *ptr = &members[1]; printf("member0 is at %p\n", ptr);` `ptr` is pointing at the second struct instance, not the first instance. 4) this: `struct memberStruct members[8192] = { 0 };` places the array in 'file global space', not on the stack – user3629249 Dec 19 '20 at 10:07
  • 1
    more comments: 1) `memcpy(ptr->Name, "Member 1 Name", 32);` the "Member 1 name" is a string in read-only memory and is only 14 bytes long. So the call to `memcpy()` will be reading from memory beyond the end of the string. The result is undefined behavior. Suggest: `strcpy( ptr->Name, "Member 1 Name" );` – user3629249 Dec 19 '20 at 10:15

2 Answers2

1

You can create the array using one call to malloc. I believe this will also store the three arrays inside of each struct in the heap as well. The return value is not the total size of the data being stored but the size of the pointer "members". Try this which doesn't use a static variable:

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

struct memberStruct {
    int Field1;
    char Name[128];
    char Token[128];
    char Secret[128];
    int Epoch;
    int Age;
    int Zip;
    int Devices;
    int Leaves;
};

void printMember(struct memberStruct *member);

int main() {
    struct memberStruct* members = (struct memberStruct*)malloc(8192 * sizeof(struct memberStruct));

    printf("size of members: %ld\n", sizeof(members));
    printMember(&members[0]);
    struct memberStruct *ptr = &members[1];
    printf("member0 is at %p\n", ptr);
    memcpy(ptr->Name, "Member 1 Name", 32);
    printMember(ptr);
    printMember(&members[1]);
    return 0;
}

void printMember(struct memberStruct *member) {
    printf("This is member at %p\n", member);
    printf("member Name: %s, Age: %d, Zip: %d, Secret: %s\n", member->Name, member->Age, member->Zip, member->Secret);
}
size of members: 8
This is member at 0x7f7ba2e68010
member Name: , Age: 0, Zip: 0, Secret: 
member0 is at 0x7f7ba2e681a8
This is member at 0x7f7ba2e681a8
member Name: Member 1 Name, Age: 0, Zip: 0, Secret: 
This is member at 0x7f7ba2e681a8
member Name: Member 1 Name, Age: 0, Zip: 0, Secret:
  • 1
    regarding: `printf("size of members: %ld\n", sizeof(members));` this is printing the size of a pointer (4 or 8 depending on the underlying hardware), not the total size of the array that `members` points toward – user3629249 Dec 19 '20 at 10:24
  • Yeah, that's why I specified in the answer it's not the total size of the data stored but instead just the pointer. – Carl Schader Dec 19 '20 at 23:36
1

regarding: Is there a way I can create this array of struct on the heap (with mem set aside for the members with fixed-length array of chars)?

currently, the array is being created in the 'file global space', not on the stack.

to create the array on the stack, then this statement:

struct memberStruct members[8192] = { 0 };

would have to be inside a function, like inside main()

to create the array on the heap use this statement, inside main():

struct memberStruct *member = calloc( sizeof( struct memberStruct ), 8192 );

which would also initialize everything to 0x00

user3629249
  • 16,402
  • 1
  • 16
  • 17
  • Thank you! Is it `struct memberStruct *member = calloc( sizeof( struct memberStruct ), 8192 );` or `struct memberStruct *member = calloc( 8192, sizeof( struct memberStruct ) );`? `*calloc(size_t nmemb, size_t size);` - Could you please explain why you had 8192 as the second arg in your example above? – struggling_learner Dec 21 '20 at 05:18
  • @struggling_learner, either way results in the same amount of heap memory being allocated – user3629249 Dec 22 '20 at 06:37