0

In the code below i was expecting another output! :

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

typedef struct _cust {
        char    customerId[10];
        char    customerPhone[10];
        char    customerDep[4];
} cust;

int main(int argc, char **argv) {
        cust    *newCust;
        const char testChar[] = "11W35A5CT-012345678-CORP";

        newCust = (cust *)malloc(sizeof(struct _cust));
        newCust = (cust *)testChar;

        printf("CustomerId = %s\n", newCust->customerId);
        printf("CustomerPhone = %s\n", newCust->customerPhone);
        printf("CustomerDep = %s\n", newCust->customerDep);

        return 0;
}

And the output is :

CustomerId = 11W35A5CT-012345678-CORP
CustomerPhone = 012345678-CORP
CustomerDep = CORP

I was expecting this output :

CustomerId = 11W35A5CT-
CustomerPhone = 012345678-
CustomerDep = CORP

Can someone explain to me why this? Thanks.

EDIT :

To avoid confusing on my post i'm adding here the gdb trace when debugging this program:

(gdb) b main
Breakpoint 1 at 0x8048474: file name.c, line 11.
(gdb) run
Starting program: /home/evariste/src/customer_files/a.out 

Breakpoint 1, main (argc=1, argv=0xbffff2c4) at name.c:11
11  int main(int argc, char **argv) {
(gdb) n
13      const char testChar[] = "11W35A5CT-012345678-CORP";
(gdb) n
15      newCust = (cust *)malloc(sizeof(struct _cust));
(gdb) n
16      newCust = (cust *)testChar;
(gdb) n
21      printf("CustomerId = %s\n", newCust->customerId);
(gdb) print *newCust
$1 = {customerId = "11W35A5CT-", customerPhone = "012345678-", 
  customerDep = "CORP"}

So whey here i see that customerId = "11W35A5CT-" and when i try printf i got the whole string?

iPadDevloperJr
  • 992
  • 3
  • 20
  • 34
  • 2
    You have a memory leak in that. You need to use memcpy, not just overwrite the pointer. Also, potentially relevant: http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule – Corbin Apr 01 '12 at 00:33
  • It doesn't apply in this case because you're only using `char`s, but you should be aware of [structure padding](http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) when interpreting raw data with structs. – James M Apr 01 '12 at 00:34
  • @corbin : Yes i know ther's a memory leak but it's not the explanation, when i do free before return it doesn't change anything. – iPadDevloperJr Apr 01 '12 at 00:38
  • @JamesMcLaughin : when i use __attribute__((__packed__)) i got the same result, so it's not a padding problem. – iPadDevloperJr Apr 01 '12 at 00:39

3 Answers3

6

printf() will output until it hits a \0 which signals the end of the string. There's no \0 after any of the hyphens and so printf() will print from the start position you gave it to the end of what's in testChar.

Also, you leaked away the memory the call to malloc allocated for you. Perhaps you want to copy the string into the struct?

QuantumMechanic
  • 13,795
  • 4
  • 45
  • 66
  • @QuantumMrchanic : it's ok for the memory leak, i'm aware of that, if your answer was ok, whey i don't have the same output three times? – iPadDevloperJr Apr 01 '12 at 00:42
  • Read Corbin's answer which will explain why you don't see the same thing three times. Short version -- because you're handing `printf` a different start position each time. – QuantumMechanic Apr 01 '12 at 00:52
2

This is a bit of an over simplification, but hopefully it will illustrate what's happening.

typedef struct _cust {
        char    customerId[10];
        char    customerPhone[10];
        char    customerDep[4];
} cust;

What the compiler will do with this is pretend it's a 24 character blob. Assume that blob is rooted at a char* called x. Then customerId is just an alias for x+0, customerPhone is an alias for x + 10, and customerDep an alias for x + 20.

So, what happening when you over write the pointer with the string is that x = testChar.

That means customerId is &testChar[0], customerPhone is &testChar[10] and so on.

The problem with this is that printf and friends, as QuantumMechanic said, do not have a concept of a range for a string. A C string is just beginning until null byte. That means that printf() on customId will go from testChar[0] until it hits a null byte which will be the end of the testchar string.

To do what you want, each string will have to have a null byte inserted at the end of it, meaning your overlay like this not going to work (also I believe your overlay could result in undefined behavior, but I'm not sure).

(Or you could do like mteckert suggested.)

Corbin
  • 33,060
  • 6
  • 68
  • 78
  • thanks i understand what the compiler do, i edit my post and i add the gdb output, please refer to it. – iPadDevloperJr Apr 01 '12 at 01:41
  • That's happening because GDB knows it's a char[10]. printf does not. – Corbin Apr 01 '12 at 02:12
  • I'm not 100% convinced :), How can i extract the value of this fileds? – iPadDevloperJr Apr 01 '12 at 02:17
  • @iPadDevloperJr I don't know why you're not convinced. That's just how C works. A pointer in C carries no information other than the address and the type. And what do you mean how can you extract? Have you read mteckert's answer? – Corbin Apr 01 '12 at 02:18
  • I want to be able to do the mapping correctly like this customerId = 11W35A5CT-, customerPhone = 012345678-, etc... – iPadDevloperJr Apr 01 '12 at 02:24
  • Then you will need to put null bytes at the end of each copied string (you won't be able to just lay the string over). – Corbin Apr 01 '12 at 02:25
0

Ditch the malloc, specify the size of the string to print in the printf format specifier.

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

typedef struct _cust {
    char    customerId[10];
    char    customerPhone[10];
    char    customerDep[4];
} cust;

int main(int argc, char **argv) {
    cust    *newCust;
    const char testChar[] = "11W35A5CT-012345678-CORP";

    newCust = (cust *)testChar;

    printf("CustomerId = %.*s\n", 
        sizeof(newCust->customerId), newCust->customerId);
    printf("CustomerPhone = %.*s\n", 
        sizeof(newCust->customerPhone), newCust->customerPhone);
    printf("CustomerDep = %.*s\n", 
        sizeof(newCust->customerDep),newCust->customerDep);

    return 0;
}
Matt Eckert
  • 1,946
  • 14
  • 16
  • Thanks for the reply, but i don't understand why this happen, normally when you cast a struct to a region of memory all the components of the struct are assigned to this region by moving the offset of each element size until reach the end. – iPadDevloperJr Apr 01 '12 at 00:46
  • `printf` doesn't care about struct components. As QuantumMechanic said, it prints until it encounters the null character. – Matt Eckert Apr 01 '12 at 00:47