简体   繁体   中英

Why does following C code print 45 in case of int 45 and 36 in case of STRING and ASCII value of CHAR?

struct s{
int a;
char c;
};
int main()
{
    struct s b = {5,'a'};
    char *p =(char *)&b;
    *p = 45;
    printf("%d " , b.a);
    return 0;
}

If *p is changes to any character than it prints ASCII value of character , if *p changed to any string ("xyz") than it prints 36 . Why it's happening ?

Can you give memory map of structure s and *p ?

According to me mamory of struct

s as z-> (****)(*) assuming 4 byte for int . and when s initialize than it would have become (0000000 00000000 00000000 00000101)(ASCII OF char a) and *p points to starting address of z . and *p is a character pointer so it will be store ASCII value at each BYTE location ie at each * will be occupied by ASCII of char . But now we make it to 45 so z would have become (45 0 0 5 )(ASCII of char a) . But it's not true why ?

your struct looks in little endian like:

00000101 00000000 00000000 00000000 01100001

so p points to the 5 and overwrite it. at the printf the 4 little endian bytes print the 45 .

if you would try it on big endian 754974725 would be the result, because p points to the MSB side of the int.

a simple test program to find out if you are on little or big endian:

int main()
{
  int a = 0x12345678;
  unsigned char *c = (unsigned char*)(&a);
  if (*c == 0x78)
    printf("little-endian\n");
  else
    printf("big-endian\n");
  return 0;
}

When you write to the struct through a char * pointer, you store 45 in the first byte of the struct. If you are on a Little-Endian implementation, you will write to the low end of ba . If you are on a Big-Endian implementation, you will write to the high end of ba .

Here is a visualization of what typically happens to the structure on an implementation with 16-bit ints, before and after the assignment *p=45 . Note that the struct is padded to a multiple of sizeof(int) .

Little-Endian

Before:  a [05][00]  (int)5
         c [61]
           [  ]

After:   a [2d][00]  (int)45
         c [61]
           [  ]

Big-Endian

Before:  a [00][05]  (int)5
         c [61]
           [  ]

After:   a [2d][05]  (int)11525
         c [61]
           [  ]

With larger ints, there are more ways to order the bytes, but you are exceedingly unlikely to encounter any other that the two above in real life.

However , The next line invokes undefined behaviour for two reasons:

printf("%d " , b.a);
  1. You are modifying a part of ba through a pointer of a different type. This may give ba a "trap representation", and reading a value containing a trap representation causes undefined behaviour. (And no, you are not likely to ever encounter a trap representation (in an integer type) in real life.)
  2. You are calling a variadic function without a function declaration. Variadic functions typically have unusal ways of passing arguments, so the compiler has to know about it. The usual fix is to #include <stdio.h> .

Undefined behaviour means that anything could happen, such as printing the wrong value, crashing your program or (the worst of them all) doing exactly what you expect.

The C standard guarantees that the address of the first member of a structure is the address of the structure. That is, in your case,

int* p =(int*)&b;

is a safe cast. But there is no standard way of accessing the char member from the address of the structure. This is because the standard does not say anything about the contiguity of successive members in memory: in fact the compiler may or may not insert gaps (called structure packing) between members to suit the chipset.

So what you're doing is essentially undefined.

Because, this

*p = 45;

Changes the value of what p points to to 45. And you made p point to b.

try this Pointers to structure.

#include<stdio.h>

    struct s{
    int a;
    char c[1];
    };

    int main()
    {
        struct s *p;
        struct s b = {5, 'a'};
        p = &b;

        printf("%d %s", p->a, p->c);
        return 0;
    }

if you want Pointers as structure member instead of an array of char. try this..

#include<stdio.h>

struct s{
int a;
char *c;
};

int main()
{
    struct s b = {5, "a"};

    printf("%d %s", b.a, b.c);
    return 0;
}

char *p = (char*) &b; - in this line, p points to the beginning of b struct as a char pointer.

*p = 45; writes 45 to the memory space of b which is can be accessed by ba as well.

when you print printf("%d ", ba); you'll print the 45 stored in the stack memory assigned as a member of struct b you'll get 45.

try debugging it yourself and you'll see it in the watch window

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM