【问题标题】:How do I make a pointer inside a struct point to the same string pointed by another pointer?如何使结构内的指针指向另一个指针指向的相同字符串?
【发布时间】:2020-12-14 04:43:25
【问题描述】:

我有以下代码:

struct el{      
    char *line;
    struct el *next;
};
struct el *abc, def;
char *p1;
char buffer[100];
abc = &def;
gets(buffer);
p1 = malloc(strlen(buffer) + 1 );
strcpy( p1, buffer);

如何使line 指向p1 所指向的同一个字符串,而不用两次分配同一个字符串?写够了吗:

 abc->line = p1;

或者我还需要释放p1指向的区域吗?

【问题讨论】:

  • 1) 不要使用gets 2) sizeof(strlen(buffer)) 完全错误
  • abc->line = p1 不会创建副本。释放 p1 也会释放另一个指针(相同的地址)
  • 使用fgets
  • @Andrea 这不是速度问题。只是它不安全,因为它不对输入的大小执行任何检查(在您的情况下,由于 buffer 的大小为 100,通过发送超过 100 个字符的输入将导致写入超出范围,这可能会使您的程序崩溃)。
  • abc->line = p1; 完全按照您的想法进行。它获取 p1 中的值(这是一个地址)并将相同的值保存到 abc->line 中。现在 abc->line 和 p1 存储相同的地址。

标签: c string pointers struct


【解决方案1】:

我感觉到有异味...也就是说,您的所有变量似乎都是局部变量(在堆栈上),当您的函数返回时它们不再存在。

你的函数也会以

结尾
return abc;

然后你失去了一切,因为你说abc= &def;def 也是一个局部变量。所以是的,你可以简单地做abc->line= p1;,但在返回之后你失去了abc(它指向def,这是一个不再存在的堆栈变量),因此你也失去了abc->line,所以你有内存泄漏。

因此,您应该扩展您向我们展示的代码,以便我们能够说“是的,您可以这样做”。

以下是错误函数的示例:

struct el{
    char *line;
    struct el *next;
};

struct el *example(void)
{
    struct el *abc, def;    // def is a local variable
    char *p1;
    char buffer[100];
        
    abc = &def;
    gets(buffer);
    p1 = malloc( strlen(buffer) + 1 );
    strcpy( p1, buffer);
    
    abc->line= p1;
    return abc;             // def won't exist anymore after the function returns
}

要修复此错误,您还应该执行abc= malloc(sizeof(struct el)); 或将指针变量传递给函数,例如:

void example2(struct el *abc)
{
    char *p1;
    // ...
    abc->line= p1;
 }

并调用例如:

int main(void)
{
    struct el pqr = {0};
    example2(&pqr);
    // ...
}

【讨论】:

  • 那么我需要使用指向指针的指针吗? @保罗奥格尔维
  • @Andrea - 不,您不需要 使用双指针来更新结构实例的值。这不是保罗在这里提供的主要信息。他指的是您在临时生命周期内创建了本地自动变量的事实。执行流程在函数内创建的堆栈位置(地址)将在离开时不复存在。
  • @Paul Ogilvie 所以假设 struct el *abc 是传递给函数的参数,当我写 abc->line = p1 时,这个赋值在返回后还会保留吗?
  • @Paul Ogilvie 我的意思是,abc->line 是否仍会指向函数内部分配的区域(p1 指向的区域)?
  • 如果函数签名是 void f(struct el *abc),那么 abc->line= p1; 是正确的。那是因为abc 不再指向局部变量。
【解决方案2】:

首先,不推荐使用gets()。一个很好的替代品是fgets()

我怎样才能让 'line' 指向 'p1' 指向的同一个字符串,而不用分配 >同一个字符串两次?

两个指针都可以指向同一个缓冲区,只需将它们设置为指向缓冲区的地址即可。不需要动态内存分配。 鉴于您的代码:

//the following are created in file global scope
struct el{
    char *line;
    struct el *next;
};

struct el *abc, def; 

char *p1;
char buffer[100];

//The following is performed in local scope within a function, using global variables created above.
p1 = &buffer[0];//assign address of buffer to pointer p1
//same for char *line:
abc->line = &buffer[0];//assign address of buffer to member *line

//both will now accept input using fgets()
fgets(p1, sizeof(buffer), stdin);
fgets(abc->line, sizeof(buffer), stdin);

【讨论】:

    【解决方案3】:

    如何使line 指向p1 指向的同一个字符串,而不用两次分配同一个字符串?写abc->line = p1够吗?

    是的。 abc->line = p1; 是正确的。

    或者我还需要释放p1指向的区域吗?

    不,一点也不。相反,如果您这样做,line 将指向任何地方。

    注意abc->line = p1;只是将malloc()分配的chunk的内存地址值从p1赋值给结构成员line。它们都是对malloc()分配的**相同**内存的引用。


    永远不要使用gets()。原因是here。自 C11 起,它也从 C 标准中删除。

    【讨论】:

      【解决方案4】:

      如何使line 指向p1 指向的同一个字符串,而不用两次分配同一个字符串?写够了吗:

      abc->line = p1;
      

      是的,你可以这样做。 abc->line 将指向与 p1 相同的内存地址。

      或者我还需要释放 'p1' 指向的区域吗?

      不,您不需要同时释放两者。您应该使用:

      free(abc->line);
      

      或:

      free(p1);
      

      你只需要其中一个,因为两个指针都指向同一个内存地址,当你释放一个时,你释放两个。

      请注意,通过释放abc->linep1 将成为一个悬空指针,它将指向没有任何意义的东西。

      Recommended read 关于gets

      【讨论】:

        猜你喜欢
        • 2018-05-16
        • 2020-03-23
        • 1970-01-01
        • 2018-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多