0

I start learning C. It is fun. But I came to the point when I was trying to play around with struct. Below you have my program which I have created and I notice that behaviour of struct is different depend on how it was created.

When I run the program below my output is surprising. Output:

1. 1 0.000000 (some strange chars)
2. 0 0.000000 (null)

First of all like you can see the output of 1, 2 is different even if it is related to the same struct. Second of all number 3 is not printed at all.

I wonder why is that? I found on stackoverflow some explanation about the c struct but non of this post touch that issue. I was wonder if that is because of compiler? Or this is normal feature of C which I have to just understand? Or do I have even think about it?

#include <stdio.h>

struct s1 {
  int int1;
  double double1;
  char *string;
} strc;

typedef struct {
  int int1;
  double double1;
  char *string;
} DStruct;

int main() {
  struct s1 defqu;
  DStruct defqu2;

  printf("1. %d %f %s\n", defqu.int1, defqu.double1, defqu.string);
  printf("2. %d %f %s\n", strc.int1, strc.double1, strc.string);
  printf("3. %d %f %s\n", defqu2.int1, defqu2.double1, defqu2.string);
  
  return 0;
}
noname
  • 565
  • 6
  • 23
  • 5
    You never initialize the values within your structs, so the memory pointed to by `char *string` could be anything. It's commonly referred to as "garbage memory." This is essentially a case of undefined behavior. You should initialize your structs. – h0r53 Oct 01 '21 at 13:39
  • @h0r53 I understand that if you not initialize and values are `garbage`, but I am more considered that the behaviour of `struct` is different. When I print `struct` in first print values are totally. Like understand the values are different, but why when I try print values in `3.` this `printf` does not appear in console. – noname Oct 01 '21 at 15:48
  • 1
    The behavior you've observed is an artifact of several factors, including your compiler, OS, and whatever happened to be in memory at runtime. This has nothing to do with the way you've declared `struct`s. It is undefined behavior by the C language standard, so you will likely see different behavior provided a different C compiler, OS, memory instance, etc. You should not stress trying to understand why the output is that way. For example, the output from GCC clang 12.0.5 on my MacBook is different than yours and `.3` does actually print data and the values for `.1` and `.2` are different. – h0r53 Oct 01 '21 at 15:57

2 Answers2

3

You never initialized the instances you create, so it contains "garbage". Hence, you can expect "unexpected behavior" :)

Change it to:


struct s1 {
  int int1;
  double double1;
  char *string;
} strc = {0};

typedef struct {
  int int1;
  double double1;
  char *string;
} DStruct;

int main() {
  struct s1 defqu = {0};
  DStruct defqu2 = {0};

  ...

The syntax = { 0 } initializes all the values in the struct to 0. From the C99 Standard:

If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

This will be better, but still not perfect. The numbers will all be initialized to 0, and the string pointers (char * to be more accurate) will be initialized to NULL.

Modern libc implementation will handle the NULL pointer you pass to %s gracefully, but that's actually undefined behavior as well.

Daniel Trugman
  • 8,186
  • 20
  • 41
  • 1
    Can you elaborate on the automatic initialization through `defqu = {0}` for educational purposes? Some may be confused by that syntax. – h0r53 Oct 01 '21 at 13:46
  • 1
    You say "the strings will be empty (since they contain only a null-terminator (0 value)" — that's inaccurate. The strings will be null pointers, not empty strings. Granted, many versions of `printf()` avoid crashing when given a null pointer for a string — personally, I think that's reprehensible behaviour from `printf()` and it should explicitly call `abort()`, or otherwise ensure that the program crashes. However, passing a null pointer to `printf()` for a string leads to undefined behaviour. – Jonathan Leffler Oct 01 '21 at 14:02
  • @JonathanLeffler, you are correct. Revised my answer. – Daniel Trugman Oct 01 '21 at 14:17
0

strc is a global variable. It's guaranteed(by C standard) to be initialized to zero. So all the members of strc will also be initialized to zero (including the string pointer). When you try to print the string in the second printf (%s), you invoke undefined behavior (dereferencing a null pointer). Most likely the program crashes/terminates when dereferencing a NULL pointer, but that's not guaranteed by the standard. Because, you know, it's undefined behavior!

defqu and defqu2 are local variables inside main function. Local variables are never auto-initialized in C. So they have some garbage value and can't be guaranteed to be zero like in the case of strc. So the string pointer points to some random memory address and the first printf, most likely, printed the characters at that random memory location. You didn't see any output from the third printf because the program crashed/exited at the second printf because of the null dereference as explained above. Move this printf to the end, you'll see the output for defqu2 too, but you can never be sure(because, undefined behavior!)

Fractal
  • 816
  • 5
  • 15
  • The wording here makes it sound as if you are implying all global variables are guaranteed to be initialized to 0. The fact that `strc` is global does not guarantee it to be initialized to zero. Global variables can clearly have non-zero values. Although, variables in the `.data` segment should be initialized to zero if no explicit initialization is given. I am not aware of a C standard for this though (citation?). – h0r53 Oct 01 '21 at 17:04
  • @h0r53 https://stackoverflow.com/questions/16015656/are-global-variables-always-initialized-to-zero-in-c – Fractal Oct 01 '21 at 17:36