Blackninja543
Blackninja543

Reputation: 3709

C Pointer Referencing

I have the following code which simply prints out an introduction for a person's name.

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

typedef struct {
    char* firstname;
    char* lastname;
}Person;

void intro(void *person){
    printf("The person you are looking for is %s %s\n", ((Person *)person)->firstname, ((Person *)person)->lastname);
}

int main()
{
    Person *a = NULL;
    a = (Person *)malloc(sizeof(Person));

    char *first = NULL, *last = NULL;
    first = (char *)malloc(sizeof(char)*20);
    strncpy(first,"Bob", 20);
    last = (char *)malloc(sizeof(char)*20);
    strncpy(last,"Newmonson", 20)
    a->firstname = first;
    a->lastname = last;

    intro(a);

    return 0;
}

Produces the output

The person you are looking for is Bob Newmonson

However changing intro(a) to intro(&a) produces

The person you are looking for is �@ Newmonson

When I open the first attempt in GDB and break on line 10 I find the address of person=0x601010. Both the first name and last name are stored where I would expect, 0x04006b9 and 0x4006bd since they where declared earlier in the stack.

What gets me is when I run GDB with the changes made to intro(&a). The address of person is now 0x7fffffffffdd38, with the first name pointing to 0x601010 and the last name pointing to 0x4006db.

Can anyone help explain to be what is going on and why I can still access the proper address of the last name in the second test.

EDIT :

As everyone seems to keep asking about it the void * was for a threading portion of this code that I did not include.

Upvotes: 2

Views: 130

Answers (4)

omi
omi

Reputation: 145

try this:

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

typedef struct {
    char* firstname;
    char* lastname;
}Person;

void intro(Person *person){
    printf("The person you are looking for is %s %s\n", (person)->firstname,   (person)->lastname);
}

int main()
{
    Person *a = NULL;
    char *first = NULL, *last = NULL;
    a = (Person *)malloc(sizeof(Person));


    first = (char *)malloc(sizeof(char)*20);
    first = "Bob";
    last = (char *)malloc(sizeof(char)*20);
    last = "Newmonson";
    a->firstname = first;
    a->lastname = last;

    intro(a);

    return 0;
}

hope it helps...

Upvotes: 0

Nik Bougalis
Nik Bougalis

Reputation: 10613

First of all:

/* allocate space for 20 characters and make 'first' point to that space. */
first = (char *)malloc(sizeof(char)*20);
/* now make 'first' point to the string Bob. Leak the memory that was allocated before. */
first = "Bob";
/* Rinse, lather, repeat. */
last = (char *)malloc(sizeof(char)*20);
last = "Newmonson";

Now to explain why using intro(&a) gives you unexpected results:

intro expects a pointer, which it assumes points to a structure of type Person. You create a pointer to a Person and then allocate space for it.

Calling intro(a) causes the pointer to Person to be passed as a pointer to void to intro, which then treats it as a pointer to Person and all is well.

Calling intro(&a) however takes the address of a and passes that in. Again, intro tries to treat it as a pointer to Person but that won't work because what you've passed is a pointer to a pointer to a Person. You're passing tomatoes to a function that thinks it's getting oranges. Both are fruit, and you will get juice, although you are probably not going to to be very happy when your breakfast is served with delicious tomato juice instead of delicious orange juice.

If you are asking why calling intro(&a) causes the first name to be mangled but the last name to be printed, the answer is because of sheer luck: the string with the last name just happened to be in the right position in memory.

Upvotes: 0

L. Cornelius Dol
L. Cornelius Dol

Reputation: 64036

It's because a is already pointer to a Person structure; therefore intro(&a) passes a pointer to that pointer, but intro() treats it's argument as a pointer to Person.

Also, if intro() is intended to work on a Person, it should declare a Person * argument, not a void *.

Upvotes: 4

Jason
Jason

Reputation: 32520

The address being held inside of the pointer variable a is not the same as the address of the actual memory location being taken up by a.

And address like 0x601010 is a "low" memory address, and is going to typically be somewhere on the heap. An address like 0x7fffffffffdd38 is a very "high" address, and will typically be on the stack. So &a is giving you the actual address of the variable a on the stack, and it is passing that value to the function, not the value 0x601010 being stored inside the pointer variable a, and representing the first address of the allocated memory buffer returned from malloc.

Upvotes: 3

Related Questions