C 函数中字符串的指针

C 函数中字符串的指针,c,string,memory-management,C,String,Memory Management,我似乎被一些基本的东西困住了。有人能告诉我为什么下一个代码: #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) {

我似乎被一些基本的东西困住了。有人能告诉我为什么下一个代码:

#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; } #包括 void Test1(char*t) { t=(char*)malloc(11); strcpy(t,“1234567890”); } 无效测试2(字符**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”); 返回t; } int main() { char*t1=NULL; Test1(t1); printf(“\nTest1:%s\n”,t1); char*t2=NULL; 测试2(&t2); printf(“\nTest2:%s\n”,t2); char*t3=(char*)malloc(11); 试验3(t3); printf(“\nTest3:%s\n”,t3); char*t4=NULL; t4=试验4(t4); printf(“\nTest4:%s\n”,t4); 返回0; } 给出此输出:

Test1: (null) Test2: 1234567890 Test3: 1234567890 Test4: 1234567890 Test1:(null) 测试2:1234567890 测试3:1234567890 测试4:1234567890 Test1函数有什么问题?为什么与Test1几乎相似的Test4可以工作呢?
更一般的问题:在函数中创建字符串并返回指向它的指针的正确方法是什么

因为你在写这个:

void Test1(char *t)
将此更改为:

 void Test1(char* &t)

只在C++中工作。此处演示:

函数参数的工作方式与您认为的不同。您通过“value”而不是“reference”传递值,这意味着一旦进入函数,对这些值的任何更改都只是该函数的本地更改,因此当函数退出时,本地更改将被丢弃

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

考虑函数:

void Test1(char *t) { t = (char *)malloc(11); strcpy(t, "1234567890"); }
…情况会有所不同。

当您将指针作为参数传递给函数时,指针是按值传递的。因此,您可以更改指向的对象,但如果您修改函数中的指针,调用方将不知道它。

在Test1中,行

void Test1( char*& t ) ; // This is a possible method signature.
t = (char *)malloc(11);
分配给变量t,该变量在函数Test1中是局部变量。main()中的变量t1未更改,因此将NULL指针传递给printf。Test4之所以有效,是因为您在main()中更改了t4


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

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

您已将t1定义为
char*t1=NULL
并将函数调用为
Test1(t1)
传递指针变量t1(不是它的地址)

函数Test1需要一个字符*
void Test1(char*t)


这里的
t
仅是
Test1
函数的局部变量。您在函数内部所做的任何修改都不会在函数外部可见,因为您实际上并没有修改
main
函数的变量
t1
,但是局部变量
t

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

char * x1 = NULL;
Test1 (x1);
测试1在以下范围内完成:

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
}

首先,在c语言中,只按值传递参数,这意味着

char *t1 = NULL;
Test1(t1);
您将指针
t1
的副本传递给函数Test1,因此修改此副本不会影响原始副本。因此,当您尝试打印字符串
t1
点时,它将是您之前初始化的空值

现在这个:

char *t4 = NULL;
t4 = Test4(t4);
虽然您也传递了
t4
副本,但函数Test4实际上为您分配了一个内存,并使
t4
副本指向该内存,然后您得到该副本,您得到分配给您的内存:)

实际上,对于Test4,您不必传递参数,只需在Test4中创建一个指针并返回它,您将获得指向所需内存的指针副本。 像这样:

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

希望这有帮助

这是一个糟糕的设计,模糊了程序的实际行为。如果开发者不理解指针,那么他们就不应该在C++中开发。不,我的意思是:通过引用总是一个坏主意。它使代码变得不清晰,并鼓励-没有必要这样做;理解指针就足够了——问题是太多程序员害怕指针,而指针实际上非常简单。@PP我不同意通过引用传递始终是个坏主意,我认为您需要更具体地说明您认为什么情况是个坏主意。不过,我也不会说这总是一件好事。请不要使用OP的例子,因为它看起来是C示例而不是C++。.PP:相反,有很多情况下,传递引用是非常非常好的想法,尤其是当您想要避免不必要的临时性时。它加快了执行速度@PP:我假设您现在只反对使用输出参数的引用,也就是说,您与用于输入参数的常量引用有很大区别(使用非常量引用会令人困惑)?@Downvoter-你是否因为我之前的评论而被否决了这应该是之前的方法签名或其他原因。谢谢。你已经标记了C++和C,这取决于你使用的是什么,在C++中你应该使用<代码> STD::String (除非有一些迫切需要不做!),在C中,除了第一种方法之外,所有的都是可能的。是的,我可以使用String类,但是我想理解核心,这就是我为什么使用的原因。
char *t4 = NULL;
t4 = Test4(t4);
   char * Test4()
   {
       char *t = (char *)malloc(11 * sizeof(char));
       strcpy(t, "1234567890");
       return t;
   }