Reputation: 3709
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
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
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
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
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