#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 -
在上面的节目中我为什么会得到&#39; 0&#39;并且mycode功能中没有显示任何数据,它应该是&#39; 10&#39;&#39; sample&#39;应该打印,程序有什么问题?,据我所知,当我们进行清理时,我不会作为参考传递,所以它不应该影响结构的本地副本。 请澄清我的疑问
答案 0 :(得分:2)
您的程序有几个未定义的行为。
第一个未定义的行为:
在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
,即使在true
中调用p
后,cleanup()
也是cleanup()
。在p
函数中,您释放指针NULL
,但将pointer
分配给MyType *
类型的局部变量p = NULL;
。相反,您应该在调用cleanup()
函数后执行{{1}}。
答案 1 :(得分:1)
据我所知,当我们进行清理时,我不会作为参考传递,因此它不应该影响结构的本地副本。请澄清我的疑问
你是部分正确的。
在“清理”中,您只有p
的副本。为其分配NULL
不会改变任何内容。
但是您将全局p
的值传递给该函数,然后调用free
。
这不会改变p
,但会释放它所指向的内存。
调用cleanup
后,您不能再次访问该内存位置。
您的期望
10
sample
基于错误的假设。 你可以获得任何价值,因为这是未定义的bahaviour。
顺便说一句: 如果内存无效,你会得到
10
sample appenddata
这是由于同样的原因。
在appenddata
中,您不会更改p
,但是在您离开该功能后更改p->b
仍然存在。
答案 2 :(得分:0)
我认为您的问题出在cleanup(p)
在打印数据之前,你不应该这样做。
答案 3 :(得分:0)
要避免与free
添加#include<stdlib.h>
相关的警告,请在清理时清理结构数据并取消引用本地指针而不是主指针。因此主指针成为悬空指针。
在demo中添加了一些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;
}