c语言 - 在指针操作中未按预期打印结构变量的值


#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 - %dn",p->a);
printf("p.b - %sn",p->b);
}
appenddata(p);
/* set the values for p and do some stuff with it */
cleanup(p);
if(p != NULL)
{
printf("p->a - %dn",p->a); << Why value I am getting is '0' here and 
printf("p.b - %sn",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 - %dn",p->a);
printf("p.b - %sn",p->b);
}
else
{
printf("p is nulln");
}
}
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",程序有什么问题?,据我所知,当我们进行清理时,我没有作为参考传递,所以它不应该影响结构的本地副本。 请澄清我的疑问

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

第一个未定义的行为:

struct type中,成员b10字符数组:

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 - %dn",p->a); << Why value I am getting is '0' here and 
printf("p.b - %sn",p->b);  << No value is printed here
}

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

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

你是部分正确的。 在"清理"中,您只有p的副本。为其分配NULL不会更改任何内容。

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

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

您的期望得到

10
sample

是基于错误的假设。 你可以得到任何价值,因为无论如何这是未定义的巴哈维。

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

10
sample appenddata

这是由于同样的原因。

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

我认为你的问题出在cleanup(p)在打印数据之前不应执行此操作。

为了避免与free向源添加#include<stdlib.h>相关的警告,在清理中,您清理结构数据并取消引用本地指针而不是主指针。 因此,主指针变为悬空指针。

在演示中添加了一些 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-  

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

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

将清理功能替换为宏

#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;
} 

最新更新