Thread: Undefined behaviour from array within struct

  1. #1
    Registered User
    Join Date
    Sep 2016
    Posts
    41

    Undefined behaviour from array within struct

    Hey everyone,

    I'm teaching myself C and I am taking some time to practice structs. It has been something that has particularly confused me, mostly because I couldn't relate the concepts back to my introduction to the concept; through a silicon labs project file made for the efm32zg222f32. Anyway, I now have an understanding of what they are and how to use them.


    SECTION A:

    On to the problem: I was getting some really weird behaviour from the second instance of test_struct in the following code:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    /*
     * 
     */
    
    
    struct test_struct {
        
        int test1;
        char test2;
        char test3;
        char test4[];
        
    };
    
    
    struct pointer_struct {
        
        int* test1;
        char* test2;
        char* test3[10];
        float test4;
        
    };
    
    
    int main(int argc, char** argv) {
    
    
        char array[] = "test"; 
        
        struct test_struct instance1; 
        struct test_struct instance2;
        
        instance1.test1 = 8;
        instance1.test2 = 'A';
        instance1.test3 = '6';
        strcpy(instance1.test4, "test string");
         
        instance2 = instance1;
    
    
        //strcpy(instance2.test4, "test string");
        
        struct pointer_struct instance3;
        
        instance3.test1 = &instance1.test1;
        instance3.test2 = &instance1.test2;    
        
        printf("i1 test 1 is: %d \n", instance1.test1);
        printf("i1 test 2 is: %c \n", instance1.test2);
        printf("i1 test 3 is: %c \n", instance1.test3);
        printf("i1 test 4 is: %s \n", instance1.test4);
        
        printf("i2 test 1 is: %d \n", instance2.test1);
        printf("i2 test 2 is: %c \n", instance2.test2);
        printf("i2 test 3 is: %c \n", instance2.test3);
        printf("i2 test 4 is: %s \n", instance2.test4);
        
        printf("i3 test 1 is: %d \n", *instance3.test1);
        printf("i3 test 2 is: %c \n", *instance3.test2);
        
        return (EXIT_SUCCESS);
    }
    It turned out that the char array I had declared in test_struct needed to have it's length defined i.e. with a number in the square brackets. like so:

    Code:
    struct test_struct {
        
        int test1;
        char test2;
        char test3;
        char test4[12];
        
    };


    Otherwise I would get the following output:

    Code:
    i1 test 3 is: 6 
    i1 test 4 is: test string <<<<<
    i2 test 1 is: 8 
    i2 test 2 is: A 
    i2 test 3 is: 6 
    i2 test 4 is: t <<<<<
    i3 test 1 is: 8 
    i3 test 2 is: A

    SECTION B:

    Initially I thought that the string simply needed to be explicitly copied over, so I strcpy'd into the test4 array of the second instance like so:

    Code:
    instance2 = instance1;
    
    
    strcpy(instance2.test4, "test string");
    But that lead to this output:

    Code:
    i1 test 1 is: 1931506803 
    i1 test 2 is: t 
    i1 test 3 is: r 
    i1 test 4 is: ing 
    i2 test 1 is: 8 
    i2 test 2 is: A 
    i2 test 3 is: 6 
    i2 test 4 is: test string 
    
    i3 test 1 is: 1931506803 
    i3 test 2 is: t
    First question: Could some kindly explain why the first instance of test_struct (discussed in section A) initialized to the appropriate size, even though it wasn't defined, but the second instance did not?

    Second question: Why did I get garbage values in the output from the strcpy described in section B? I understand that because the size was undefined that it's inevitably going to spill over to other allocated space, but why did it do that in the first instance but not the second?



    Thanks in advance.
    Medicineman25

  2. #2
    Registered User
    Join Date
    May 2009
    Posts
    3,688
    You need to read up on pointers; but, I am NOT able to explain what you need to know.

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  3. #3
    Registered User
    Join Date
    Sep 2016
    Posts
    41
    @Tim S. Um ok. This question wasn't really about pointers but that's cool, is there something that is jumping out at you from the pointer sections of this code? I feel I have a pretty good grasp on implementing pointers at this stage, but I'm always keen on learning some more tricks.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,537
    All the problems you were seeing were all down to not having enough space in your struct to contain a string.

    The notation with an empty array [] at the end of a struct is called a flexible array member.
    Flexible array member - Wikipedia, the free encyclopedia

    It doesn't reserve any space (and more importantly, doesn't reserve space dynamically). So all your strcpy calls onto various instances of your struct just overwrite someone else's memory, with a variety of effects.

    The FAM allows you to do things like
    Code:
    struct message {
      int length;
      char data[];
    };
    ...
    struct message *msg = malloc( sizeof(*msg) + length*sizeof(char) );
    // now do things with msg->data[0] ... msg->data[length-1]
    > Could some kindly explain why the first instance of test_struct (discussed in section A) initialized to the appropriate size, even though it wasn't defined, but the second instance did not?
    You're confusing success with dumb luck. It worked because you were lucky, not because you were right.

    With a char array of at least 12 (as your second example), then this would work just fine
    Code:
        strcpy(instance1.test4, "test string");
          
        instance2 = instance1;
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Sep 2016
    Posts
    41
    >All the problems you were seeing were all down to not having enough space in your struct to contain a string.

    Yeh I figured that much out. Was just curious why it manipulated the instance that I wasn't manipulating. That is definitely not success by any means haha. But I guess undefined behaviour is... undefined.

    Flexible Array Member. Thank you for that piece of information. I know that dynamic arrays are frowned upon in C unless written a very specific way. I'll have to spend more time learning about those ways.

    Thanks Salem.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Undefined variable behaviour
    By MartinR in forum C Programming
    Replies: 10
    Last Post: 11-12-2015, 08:13 AM
  2. undefined behaviour
    By Saurabh Mehta in forum C Programming
    Replies: 8
    Last Post: 01-09-2013, 08:45 PM
  3. undefined behaviour.
    By juice in forum C Programming
    Replies: 3
    Last Post: 12-21-2011, 01:03 PM
  4. Undefined array in struct
    By WhiteVanMan in forum C Programming
    Replies: 3
    Last Post: 01-22-2007, 02:56 PM
  5. Is this undefined behaviour?
    By caduardo21 in forum C Programming
    Replies: 4
    Last Post: 01-15-2006, 12:55 PM

Tags for this Thread