1

I need to inizialize my array of struct with all at zero

my struct:

typedef struct stud
{
    char nome[60];
    int num;
    int nota;
} Student;

typedef Student* CLASS;

I have this code:

int main(){
    CLASS cls;
    cls = (CLASS) calloc(100,sizeof(Student));
    if (cls==NULL) printf("Error allocating memory");
}

Shouldn't calloc initialize all content from cls at zero? If i print cls or cls[0] i get garbage values;

skills
  • 315
  • 5
  • 17
  • calloc does fill the memory with zeroes. How are you printing it exactly? – mtijanic May 12 '15 at 16:34
  • 1
    Show how you are printing the pointer `cls`? – Gopi May 12 '15 at 16:35
  • After you both making reference to how i was printing it, i found out that the problem was that! Thank you very much. @mtijanic , could you answer that so i can mark as the right answer? – skills May 12 '15 at 16:40
  • in C, the returned value from calloc(), and family of functions, should not be cast. – user3629249 May 12 '15 at 16:46
  • @user3629249, if i don't cast, will the value returned from calloc be a pointer for a Student struct type, to the memory allocated? – skills May 12 '15 at 16:56
  • @skills There's a difference between 'should not' and 'cannot', you can cast it. He means it is not recommended, mostly because it can hide an error. – Zach P May 12 '15 at 16:59
  • In C the type returned by `calloc()` is `void*` so that you can assign it to any pointer type. http://stackoverflow.com/questions/1565496/specifically-whats-dangerous-about-casting-the-result-of-malloc – Weather Vane May 12 '15 at 17:01

1 Answers1

1

Since there was a discussion on how this could have happened, here is an explanation of the code in the original post.

typedef struct stud
{
    char nome[60];
    int num;
    int nota;
} Student;
// This structure is most likely 68 bytes in size:
// sizeof(Student) == 68
// offsetof(Student, nome) == 0
// offsetof(Student, num) == 60
// offsetof(Student, nota) == 64

int main(){
    // Allocate an array of 100 Students, for a total of 6800 bytes.
    // Note that calloc fills the memory with zeroes.    
    Student *cls = calloc(100, sizeof(Student));
}

Right now we have an array of 6800 bytes filled with zeroes.

Let's go through all the options of printf("%s") arguments.

"%s" expects a char* pointer to a null-terminated string. Since printf is a variable arguments function, it doesn't know the true type of the argument, it will just assume them.

Note that some compilers can check the arg types, but that isn't part of the language.

printf("%s", cls);

Here, cls points to the start of an array of 6800 zero-bytes. ((char*)cls)[0] == '\0', so it terminates immediately, and nothing is printed.

printf("%s", cls[0]);

Since (char*)(cls[0]) is a null pointer, this will crash with a null pointer dereference. The program will crash, but no garbage would be printed out.

printf("%s", cls[0]->nome);

This is actually equivalent to the first print, just cast to a different type. But since printf infers type info from the format string, not the arguments, it acts the same.

printf("%s", &cls[5]->num);

This would generally be a bad idea, but it still would print nothing. That is because the pointer points to somewhere in the zero-initialized array, meaning that when dereferenced, you'd still hit a zero first.

The only way to print out garbage is with:

printf("%s", &cls);

Here we pass a pointer to cls, and say it's a pointer to a char array. Assuming calloc returned 0xdeadbeef, when dereferencing the double pointer, we'd be treating the address as a string, so printf would print out the ASCII values of 0xef, 0xbe, 0xad, 0xde and whatever comes after it, until it either hit a 0x00 or moved hit an address not belonging to the process and caused an access violation. The first scenario is much more likely.


EDIT: Apparently the other answer and the thread with the discussion was deleted. I'll leave this here for future visitors.

mtijanic
  • 2,872
  • 11
  • 26