2012-12-05 65 views
2

我有下面的代码,它只是打印出一个人的名字的介绍。C指针参考

#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; 
} 

产生输出

The person you are looking for is Bob Newmonson

但是改变intro(a)intro(&a)产生

The person you are looking for is �@ Newmonson

当我打开GDB的第一次尝试,并在第10行打破我找到地址person=0x601010。名字和姓氏都存储在我预期的地方,0x04006b90x4006bd,因为它们是在堆栈中早些时候声明的。

什么让我是当我运行GDB与intro(&a)的变化。 person的地址现在是0x7fffffffffdd38,第一个名字指向0x601010,姓氏指向0x4006db

任何人都可以帮助解释是怎么回事,为什么我仍然可以在第二次测试中访问姓氏的正确地址。

编辑:

至于大家似乎一直在问关于它的void *是这个代码,我没有包括的螺纹部分。

+4

FYI:'第一=(的char *)malloc的(的sizeof(char)的* 20);第一个=“鲍勃”;“没有做你认为正在做的事情。 –

+1

另外,为什么当声明'intro()'是否只有一个''* *'的时候,有一个希望与它一起工作的'void *'? –

+0

@MichaelBurr我想用'void *'来进行练习,但碰到了这个问题。 – Blackninja543

回答

4

这是因为a已经指向Person结构;因此intro(&a)会将指针传递给该指针,但intro()将其参数视为指向Person的指针。

此外,如果intro()打算在人员上工作,则应声明Person *参数,而不是void *

+0

'void *'位是巧合的,因为它最初与这个问题无关。 – Blackninja543

+0

@ Blackninja543:实际上,'void *'是重要的 - 如果函数被更好地声明,编译器在使用'intro(&a)'时会警告你指针类型不匹配。应该避免使用'void *' - 它需要的是一个大红旗,因为某些事情是错误的。 –

3

指针变量a内部保存的地址与a占用的实际内存位置的地址不同。

0x601010这样的地址是一个“低”内存地址,并且通常会在堆上的某个地方。像0x7fffffffffdd38的地址是一个很“高”的地址,通常会在堆栈中。所以&a是给你堆栈上的变量a的实际地址,它是传递一个值的函数,而不是价值0x601010存储指针变量a内,并表示被分配的内存缓冲区的首地址从返回malloc

0

首先:

/* 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"; 

我们解释为什么使用intro(&a)给你意想不到的结果:

intro预期的指针,它假设点Person型的结构。您创建一个指向Person的指针,然后为其分配空间。

调用intro(a)使指针Person到作为指针以void引导页,然后将其视为一个指针Person和一切正常传递。

调用intro(&a)但需要的a地址并通过在再次,intro试图把它当作一个指向Person但不会工作,因为你已经通过一个指针的指针一个Person。你正在将西红柿传递给认为它变成橘子的功能。两种都是水果,你会得到果汁,虽然你可能不会很高兴,当你的早餐与美味的番茄汁,而不是美味的橙汁服务。

如果你问为什么调用intro(&a)会导致名字被破坏,但要打印的姓氏,答案是因为运气好:带姓的字符串恰好在内存中的正确位置。

0

试试这个:

#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; 
} 

希望它可以帮助...

+0

你为什么要将'Person *'投射到'Person *'? –

+0

我知道它不必要,但我相信它的好习惯,平静编译器:P – omi

+0

再来一次?我不知道这意味着什么。 –