2011-01-07 156 views
3

看来我是被卡住了一些基础知识。有人可以解释我为什么下面的代码:指针,指向函数的字符串

 
#include <stdlib.h> 

void Test1(char *t) 
{ 
    t = (char *)malloc(11); 
    strcpy(t, "1234567890"); 
} 

void Test2(char **t) 
{ 
    *t = (char *)malloc(11); 
    strcpy(*t, "1234567890"); 
} 

void Test3(char *t) 
{ 
    strcpy(t, "1234567890"); 
} 

char * Test4(char *t) 
{ 
    t = (char *)malloc(11); 
    strcpy(t, "1234567890"); 
    return t; 
} 

int main() 
{ 
    char *t1 = NULL; 
    Test1(t1); 
    printf("\nTest1: %s\n", t1); 

    char *t2 = NULL; 
    Test2(&t2); 
    printf("\nTest2: %s\n", t2); 

    char *t3 = (char *)malloc(11); 
    Test3(t3); 
    printf("\nTest3: %s\n", t3); 

    char *t4 = NULL; 
    t4 = Test4(t4); 
    printf("\nTest4: %s\n", t4); 

    return 0; 
} 

给出了这样的输出:

 
Test1: (null) 

Test2: 1234567890 

Test3: 1234567890 

Test4: 1234567890 

这有什么错Test1的功能?为什么Test4与Test1几乎相似? 更一般的问题:在函数中创建字符串并返回指针的正确方法是什么?

+2

您已经标记了C++和C,而这取决于在C++中,你应该使用`std :: string`(除非有一些迫切需要!),在C中,除了第一种方法都是可能的。 – Nim 2011-01-07 14:52:33

+0

是的,我可以使用字符串类,但我想了解核心,这就是为什么我在这里使用char *。 – clumpter 2011-01-07 15:46:23

+0

在C中,do * NOT *强制转换了`malloc()`的结果。在这里阅读推理:http://stackoverflow.com/a/605858/1701799(基本上,这是因为一个`void *`会自动安全地升级到适当的类型)。我知道这被标记为C/C++,但没有这样的语言“C/C++”。如果这是C++,那么您将使用`#include `而不是`#include `。我认为这应该只是被标记为C.在C++中,你几乎不会使用`malloc()```free()`,而是使用`new/delete`,或者更好的智能指针/ etc .. – RastaJedi 2016-02-22 05:35:12

回答

0

考虑你的Test1执行以下行为:

char * x1 = NULL; 
Test1 (x1); 

Test1的是以下中完成:

void test1 (char * t)// t -> x1 -> null 
{ 
    t = (char *) malloc (11); 
    // t now points a different place (the memory allocated), and the reference of x1 continues pointing to null 
    strcpy (t, "1234567890"); // t value is "1234567890" but x1 continues pointing to null 
    // Error, the memory that is pointed by t is never released 
} 
printf ("\nTest1:%s \n", t1);// Print the value of x1 (null) and the reference of t is lost 
1

因为你写的:

void Test1(char *t) 

更改为:

void Test1(char* &t) 

将在C++中唯一的工作。示范这里:http://www.ideone.com/OYNQo

+2

只有在C++请。 – Benoit 2011-01-07 14:40:13

6

函数参数不工作,你的思考方式。你的价值路过的“价值”,而不是“参考”,这里面的功能意味着一旦,这些值的任何变化都只是局限于该功能,所以当函数退出的局部变化被扔掉。

要解决此问题,请将指针传递给指针(char ** t),或者通过引用传递指针(char & *)并更改要匹配的函数代码。

2

考虑函数:

 
void Test1(char *t) 
{ 
    t = (char *)malloc(11); 
    strcpy(t, "1234567890"); 
} 

现在,t是函数内的一个局部变量。它包含什么?指针值。最初那个指针值指向NULL,因为你把它叫做Test1(NULL);

然而第一行,t = (char *)malloc(11),所述局部变量t重新分配给新malloc分配一块存储器。

当函数返回时您main()变量t1仍然指向NULL,因为记得我之前说的,在Test1函数采用指针的值的副本。在任何时候,t1变量都不会被Test1修改。

但是,如果你编码的功能等:

 
void Test1(char **t) { 
    *t = (char *)malloc(11); 
    strcpy(*t, "1234567890"); 
} 

int main(void) { 
    ... 
    Test1(&t1); 
    ... 
} 

..things会有所不同。

2

当传递一个指针作为参数传递给功能时,指针由值来传递。因此,您可以更改指向的对象,但是如果修改函数中的指针,调用者将不会知道它。

0
void Test1(char*& t) ; // This is a possible method signature. 
1

在测试1中,线

t = (char *)malloc(11); 

分配给变量T,这是在功能测试1本地。main()中的变量t1没有改变,所以传递给printf的NULL指针。 Test4可以工作,因为你在main()中改变了t4。

在函数中创建字符串的“正确”方法是Test4(但不需要提供t作为参数)或Test2(如果您更喜欢或需要out参数)。在这两种情况下,主叫方都必须随后释放该字符串。 Test3也可以工作,但调用者必须确保缓冲区足够大 - 为了防止未定义的行为和内存泄漏,缓冲区大小应作为参数传递给Test3。使用Test3的优点是可以将缓冲区分配到堆栈中,消除了内存泄漏的风险。

2

Test1中,您将变量t传递给您的函数,该函数是一个指针。 传递给函数的参数存在于堆栈中,当函数完成时,堆栈会丢失。你main()中的t为NULL的原因是你将malloc的结果存储在堆栈中,并且该堆栈不再存在。

3

您已经定义了T1作为 char* t1 = NULL; 和调用功能 Test1(t1); 传递指针变量T1(而不是它的地址)。

功能的Test1期待一个char * void Test1(char *t)

这里t是一个局部变量只Test1功能。在函数内部进行的任何修改都不会在函数的外侧显示,因为您实际上并未修改main函数的变量t1,而是本地变量t