简体   繁体   中英

Segmentation Fault in C dereferencing pointers

I am trying to understand pointers and char arrays in C programming. I have a struct called player defined as such:

typedef struct player{
    char* name;
    float ppm;
} player;

And I have the following in Main:

int main()
{
  player* head = (player*) malloc(sizeof(player));
  char* meName = &(head->name);
  (*head).name = "potato";
  (*head).name = "Paul";
  (*head).ppg =7.6;
  //printf("player is named %s\n", *meName); //First print
  printf("player is named %s\n", meName); //second print
  printf("player is named %s\n", (*head).name); //third print
  return 0;
}

Why does my first print cause a segmentation fault, and why do my other two prints output the following:

player is named k0@
player is named Paul

If I am not mistaken meName should be pointing to a memory address that is then changed by using another pointer to that same memory address. In fact, if I print it as in my 2nd print, it shows that address. Why is dereferencing it cause for a segFault when I clearly set the variable to point to a memory space that was altered right after? Why would it not change to Paul ? And why would it throw a segfault in the first place?

Also, I'd appreciate an explanation of the arrow -> vs the * used to dereference pointers.

This is incorrect, and you should get a warning:

char* meName = &(head->name);

meName is a pointer to a pointer to char , not simply a pointer to char . Here is how you can fix it:

char** meName = &(head->name);

Of course printing should look like this - ie the way that you have commented out:

printf("player is named %s\n", *meName);

First off all your printfs use the %s code. That means the second argument will be interpreted as a pointer to (ie the address of) a byte representing a character. Printf will print the value of that byte (as a character), then the value of the next byte in memory, and so on until it encounters a byte whose value is 0.

I'll take your print statements one at a time.

printf("player is named %s\n", *meName);

The *meName means the character at location meName . This character will be an integer between -128 and +127. (In fact it is 107 -- see below.) Now you are using this number, 107, as if it were the address of (the first character of) a null-terminated string. Chances are that this number is not a valid address, so when printf tries to read the character at that address (107), it's outside of your process's memory range and so you get a segmentation fault. (Usually segmentation fault means you've tried to read or write memory at an address your process is not allowed to access.)

Second

printf("player is named %s\n", meName);

This is better because meName is at least a pointer. So what does it point to. The initialization

meName = &(head->name);

means that meName is the address of (ie points to) the field head->name . Note that this is not actually a character, it is a pointer to a character. So what happens is that printf prints out the first byte of the head->name as if it were a character. It happens to print as k , so that first byte is 107 (the ascii number for a k ). Then it prints the second byte of the pointer, and so on until there happens to be a byte that is 00000000. Why your compiler accepted the initialization is not clear to me, as the type on the left is "pointer to character" and the type on the right is "pointer to pointer to character". It should have generated at least a warning error.

Third printf

printf("player is named %s\n", (*head).name);

This looks at address head and finds a structure. The value of the name field of that structure is the address of the first byte of a five byte sequence 'P' 'a' 'u' 'l' 0. printf follows this pointer value to find the 'P' (which it prints), then it increments the pointer, and follows it again to find the 'a' , and so on until it finds the 0 byte and at that point it stops.

Note that because printf is a bit special, its arguments are not type checked by the compiler. That is why your first printf compiled even though the type of the second argument was not char* as the %s directive indicates it should be.

int main()
{
  player* head = (player*) malloc(sizeof(player));
  char* meName = &(head->name);
  (*head).name = "potato";
  (*head).name = "Paul";
  (*head).ppg =7.6;
  //printf("player is named %s\n", *meName); //First print
  printf("player is named %s\n", meName); //second print
  printf("player is named %s\n", (*head).name); //third print
  return 0;
}

This code has serious type errors (some of which would be caught by the compiler if you used appropriate warning levels) and does not use best practices (and also won't compile due to typos). Contrast it to

int main(void)
{
  player* head = malloc(sizeof *head);
  char** pname = &head->name;

  head->name = "potato";
  head->name = "Paul";
  head->ppm = 7.6;

  printf("address of player name is %p\n", pname);
  printf("player is named %s\n", *pname);
  printf("ditto: %s\n", head->name);

  return 0;
}

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