【问题标题】:Value of structure variable is not printing as expected in pointer operation结构变量的值在指针操作中未按预期打印
【发布时间】:2018-03-29 07:00:30
【问题描述】:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct type {
    int a;
    char b[10];
}MyType;

MyType* p;
void appenddata(MyType* p);
void cleanup(MyType* pointer);

void mycode() {
  p = (MyType *)malloc(sizeof(MyType));

  if(p != NULL)
  {
    p->a = 10;
    strcpy(p->b, "sample");
    printf("p->a - %d\n",p->a);
    printf("p.b - %s\n",p->b);
  }

  appenddata(p);

  /* set the values for p and do some stuff with it */
  cleanup(p);
  if(p != NULL)
  {
    printf("p->a - %d\n",p->a); << Why value I am getting is '0' here and 
    printf("p.b - %s\n",p->b);  << No value is printed here
  }

}

void appenddata(MyType* p)
{
  if(p != NULL)
  {
    p->a = 10;
    strcpy(p->b, "sample appenddata");
    printf("p->a - %d\n",p->a);
    printf("p.b - %s\n",p->b);
  }
  else
  {
      printf("p is null\n");
  }
}

void cleanup(MyType* pointer) {
  free(pointer);
  pointer = NULL;
}

int main()
{
    printf("Hello, World!\n");
    mycode();
    return 0;
}

输出:

Hello, World!
p->a - 10
p.b - sample
p->a - 10
p.b - sample appenddata
p->a - 0
p.b - 

在上面的程序中为什么我得到'0'并且mycode函数中没有显示数据,它应该是'10'并且应该打印'sample',程序有什么问题?据我所知我们什么时候做清理然后我没有作为参考传递,所以它不应该影响结构的本地副本。 请澄清我的疑问

【问题讨论】:

  • 您正在关注p#include &lt;stdlib.h&gt;。打开警告。
  • 即使在解决了 Keine 指出的问题之后,pointer = NULL;cleanup 中也毫无意义。所做的只是将一个局部指针变量设置为NULL;调用方提供的参数将保持不变(尽管它将持有一个现在悬空的无效指针值)。

标签: c pointers malloc structure


【解决方案1】:

您的程序有几个未定义的行为。

第一个未定义的行为:

struct type 中,您有成员b 作为10 字符数组:

char b[10];

在函数appenddata() 中,您正在将长度超过10 字符的字符串复制到b

strcpy(p->b, "sample appenddata");
              ^^^^^^^^^^^^^^^^^

越界访问数组是未定义的行为。

要解决此问题,请增加数组 b 的大小,例如 b[50],并使用 strncpy,它可以让您控制要复制到目标的字符数。使用之前请仔细阅读strncpy

第二个未定义的行为:

当你释放一个动态分配的内存块时,它的生命周期就结束了。

来自 C 标准#6.2.4p2

对象的生命周期是程序执行期间保证为其保留存储的部分。一个对象存在,具有一个常量地址,33) 并在其生命周期内保留其最后存储的值。34) 如果对象在其生命周期之外被引用,则行为未定义。当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定[强调我的]

在这里,您在释放 p 后访问它:

  if(p != NULL)
  {
    printf("p->a - %d\n",p->a); << Why value I am getting is '0' here and 
    printf("p.b - %s\n",p->b);  << No value is printed here
  }

这会导致未定义的行为。这是因为 if 条件 p != NULL 即使在 cleanup() 中调用释放 p 之后也是 true。在cleanup() 函数中,您正在释放指针p,但将NULL 分配给MyType * 类型的局部变量pointer。相反,您应该在调用cleanup() 函数后执行p = NULL;

【讨论】:

    【解决方案2】:

    据我所知,当我们进行清理时,我不会作为参考传递,因此它不应该影响结构的本地副本。请澄清我的疑问

    你说对了一部分。 在“清理”中,您只有p 的副本。将NULL 分配给它不会改变任何东西。

    但是你将全局p 的值传递给函数,然后调用free。 这不会改变p,但会释放它指向的内存。

    调用cleanup 后,您将无法再次访问该内存位置。

    你期望得到

    10
    sample
    

    是基于错误的假设。 您可以获得任何价值,因为无论如何这都是未定义的行为。

    顺便说一句: 如果内存不是无效的,你会得到 ​​p>

    10
    sample appenddata
    

    这是由于同样的原因。

    appenddata 中,您不会更改p,但您会更改p-&gt;b,它在您离开函数后仍然存在。

    【讨论】:

    • 即使我获取“MyType* p;”的本地副本在 mycode 函数中,我得到相同的结果!!! #格哈德
    • 如果您的p 是全局p 的副本,那么它将指向相同的内存并导致完全相同的问题。
    【解决方案3】:

    我认为您的问题出在cleanup(p) 在打印数据之前不应该这样做。

    【讨论】:

      【解决方案4】:

      为了避免与free 相关的警告,请将#include&lt;stdlib.h&gt; 添加到源代码中,在清理过程中,您需要清理结构数据并取消引用本地指针而不是主指针。因此主指针变成了悬空指针。

      在演示中添加了一些 printf:

      Hello, World!
      p->a - 10
      p.b - sample
      p->a - 10
      p.b - sample appenddata
      Pointer Address before cleanup : 0x14a5020
      Pointer Address before free : 0x14a5020
      Pointer Address after free : (nil)
      Pointer Address after cleanup : 0x14a5020
      p->a 1- 0
      p.b 2-  
      

      因此试图打印指向的悬空指针的垃圾。

      为了避免你可以做任何一种方式。

      将清理函数替换为 MACRO

      #define cleanup(p) free(p); p=NULL
      

      或者从清理函数返回指针

      MyType* cleanup(MyType* pointer);
      
      ....................
       /* set the values for p and do some stuff with it */
      p = cleanup(p);
      .......................
      
      MyType* cleanup(MyType* pointer) {
      
        free(pointer);
        pointer = NULL;
        return pointer;
      } 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-12-11
        • 1970-01-01
        • 1970-01-01
        • 2020-07-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多