关于指针的一个问题,疑惑

时间:2021-09-06 20:06:00
#include<stdio.h>
char *a(void)
{
char s[]="nksndl";
 
return s;
}
main()
{
char *p=NULL;
 
p=a();
printf("%s\n",p);


为什么输出是乱码?

25 个解决方案

#1


char s[]这个变量是在局部函数里面定义和赋值的
当程序退出这个函数时,s会被清理掉的

#2


因为你的变量s是函数的局部变量,因此函数结束时,s的生命周期也结束了,其指向的地址空间也就无效了。

#3


char s[]="nksndl";
改为:static char s[]="nksndl";

#4


return 语句不可返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数
体结束时被自动销毁

#5


char s[]="nksndl";

改为
char *pS ="nksndl";

#6


引用楼主 jsyooo 的回复:
#include<stdio.h>
char *a(void)
{
char s[]="nksndl";
 
return s;
}
main()
{
char *p=NULL;
 
p=a();
printf("%s\n",p);


为什么输出是乱码?


但是我单步跟踪过,他传回来的地址是正确的,并且地址里面的内容也没有改变,
并且在main()里用printf("%c\n",*p); 可以一个一个的输出字符串中的内容。

#7


引用 1 楼 daoxwj 的回复:
char s[]这个变量是在局部函数里面定义和赋值的
当程序退出这个函数时,s会被清理掉的
但是我单步跟踪过,他传回来的地址是正确的,并且地址里面的内容也没有改变,
并且在main()里用printf("%c\n",*p); 可以一个一个的输出字符串中的内容。

#8


char s[]="nksndl";

改成
 static char s[]="nksndl";

#9


你返回的是指针的地址,把接口的类型改成char*而不是char

#10


指针的地址 ,赋值给char类型,基本就是乱码吧

#11


引用 7 楼 jsyooo 的回复:
引用 1 楼 daoxwj 的回复:
char s[]这个变量是在局部函数里面定义和赋值的
当程序退出这个函数时,s会被清理掉的
但是我单步跟踪过,他传回来的地址是正确的,并且地址里面的内容也没有改变,
并且在main()里用printf("%c\n",*p); 可以一个一个的输出字符串中的内容。


不要被表象所迷惑,地址是对的,内容已经被释放了,有可能指向的地址的内容还是暂时对,那是还没有被重写。

像这类获取缓存的函数最好这样写
char *a(void)
{
char* s = new char[n]; //n是申请的字节数
... //处理缓冲区内容
return s;
}

这类函数用完一定要带一个Release函数。
void a_release(char*s)
{
delete [] s;
}

大家都知道好多函数用完一定要release,大都是这个道理。

#12


引用 9 楼 chenjiawei007 的回复:
你返回的是指针的地址,把接口的类型改成char*而不是char

返回的是哪个指针的地址?没想明白

#13


改成
 static char s[]="nksndl";

#14


谢谢各位的回答,我不是要一个解决方法(这个解决方法自己也可以想到),而是出现乱码的原因

#15


引用 14 楼 jsyooo 的回复:
谢谢各位的回答,我不是要一个解决方法(这个解决方法自己也可以想到),而是出现乱码的原因

字符数组的情况与一般的变量是不同的。
比如:
int a(void)
{
int s=1;
return s;
}
main()
{
int b; 
p=a();
printf("%d\n",p);
}这样的代码没有问题,因为在return s时,会产生一个临时的变量将s的值复制进去,然后给b。
但是问题在于你的代码中return s;时,s是数组名,其实只是一个地址,复制时也只会复制这个地址,并不会将整个数组的内容都复制下来,所以main中的char *p得到的只是一个地址,而局部变量在函数结束之后就会被收回,所以这个地址已经是无效的了。
你上面的代码有可以是乱码,有可能不是乱码,取决于这块已经被收回的地址的内容有没有被写入新的内容,这个基本上是随机的。

#16


p=a();
程序运行到这里时,p里面的确就是"nksndl",虽然临时变量被释放掉了,但只要内存没有被重新写入,则会一直保留,当你执行如下语句的时候:
printf("%s\n",p);
注意,printf是一个函数,一进入这个函数的时候,会申请一些变量(可以调试进去看),这些申请的变量将写入原来"nksndl"所占的内存,所以是乱码(因为被重写了);

当你执行如下语句的时候:
printf("%c\n",*p);
由于*p是在调用printf函数之前运算的,也就是说,先计算*p,得到一个字符,然后将这个字符传入printf函数,而这个字符可是按值传递的,所以到了printf函数里面,就算"nksndl"被重写,已经不影响到输入的值了,这个输入的值(就是字符n)已经与内存地址p没有关系了,相当于:
p=a();
char c = *p;
printf("%c\n", c);

#17


引用 14 楼 jsyooo 的回复:
谢谢各位的回答,我不是要一个解决方法(这个解决方法自己也可以想到),而是出现乱码的原因

指向已经释放了的内存空间,值已经是不可预料的了,出现了乱码有什么奇怪?

#18


引用 16 楼 yang79tao 的回复:
p=a();
程序运行到这里时,p里面的确就是"nksndl",虽然临时变量被释放掉了,但只要内存没有被重新写入,则会一直保留,当你执行如下语句的时候:
printf("%s\n",p);
注意,printf是一个函数,一进入这个函数的时候,会申请一些变量(可以调试进去看),这些申请的变量将写入原来"nksndl"所占的内存,所以是乱码(因为被重写了);

当你执行如下语句的时候:
p……



仔细看了你的回答,感觉有点明白了,但是我还试了试用for循环 依次执行printf(“c%”,*p++);也能输出整个字符串,难道在这个过程当中前面一次的printf函数的执行没有修改掉字符串的值?

#19



char* fun()
{
char buff[] = "123456";
return buff;
}

char* p = fun();
int n = strlen(p);
for (i = 0; i < n; ++i)
{
printf("%c\n", *p++);
}


是这样吗?只有第一个不是乱码,后面的都是乱码。你的代码怎样?注意,如果你这样:
printf("%c %c %c\n", *p, *(p + 1), *(p + 2));
打出来的,都是正常的字符,原因我在上一贴已经说过了。

#20


函数结束时销毁栈,因此你不能返回栈上的指针,除非你new出来的

#21


看来问题已经解决了。。。。返回千万别放回指向局部变量的指针

#22


引用 19 楼 yang79tao 的回复:
C/C++ code

char* fun()
{
    char buff[] = "123456";
    return buff;
}

char* p = fun();
int n = strlen(p);
for (i = 0; i < n; ++i)
{
    printf("%c\n", *p++);
}



是这样吗?只有第一个不是乱码,后……
当然是这样,我也不至于那么笨,呵呵

#23


这就是所谓的野指针,该内存地址的内容已经被系统回收,其内容具有不确定性。

#24


把你的完整代码贴上来,无论是理论上,还是我自己实际操作,都是乱码(只有第一个字符是正常的)。

#25


引用 24 楼 yang79tao 的回复:
把你的完整代码贴上来,无论是理论上,还是我自己实际操作,都是乱码(只有第一个字符是正常的)。

以前的代码弄丢立刻,现在重新写了一个,确实是乱码,可能我以前程序哪里弄错了,现在明白了,谢谢你的回答。

#1


char s[]这个变量是在局部函数里面定义和赋值的
当程序退出这个函数时,s会被清理掉的

#2


因为你的变量s是函数的局部变量,因此函数结束时,s的生命周期也结束了,其指向的地址空间也就无效了。

#3


char s[]="nksndl";
改为:static char s[]="nksndl";

#4


return 语句不可返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数
体结束时被自动销毁

#5


char s[]="nksndl";

改为
char *pS ="nksndl";

#6


引用楼主 jsyooo 的回复:
#include<stdio.h>
char *a(void)
{
char s[]="nksndl";
 
return s;
}
main()
{
char *p=NULL;
 
p=a();
printf("%s\n",p);


为什么输出是乱码?


但是我单步跟踪过,他传回来的地址是正确的,并且地址里面的内容也没有改变,
并且在main()里用printf("%c\n",*p); 可以一个一个的输出字符串中的内容。

#7


引用 1 楼 daoxwj 的回复:
char s[]这个变量是在局部函数里面定义和赋值的
当程序退出这个函数时,s会被清理掉的
但是我单步跟踪过,他传回来的地址是正确的,并且地址里面的内容也没有改变,
并且在main()里用printf("%c\n",*p); 可以一个一个的输出字符串中的内容。

#8


char s[]="nksndl";

改成
 static char s[]="nksndl";

#9


你返回的是指针的地址,把接口的类型改成char*而不是char

#10


指针的地址 ,赋值给char类型,基本就是乱码吧

#11


引用 7 楼 jsyooo 的回复:
引用 1 楼 daoxwj 的回复:
char s[]这个变量是在局部函数里面定义和赋值的
当程序退出这个函数时,s会被清理掉的
但是我单步跟踪过,他传回来的地址是正确的,并且地址里面的内容也没有改变,
并且在main()里用printf("%c\n",*p); 可以一个一个的输出字符串中的内容。


不要被表象所迷惑,地址是对的,内容已经被释放了,有可能指向的地址的内容还是暂时对,那是还没有被重写。

像这类获取缓存的函数最好这样写
char *a(void)
{
char* s = new char[n]; //n是申请的字节数
... //处理缓冲区内容
return s;
}

这类函数用完一定要带一个Release函数。
void a_release(char*s)
{
delete [] s;
}

大家都知道好多函数用完一定要release,大都是这个道理。

#12


引用 9 楼 chenjiawei007 的回复:
你返回的是指针的地址,把接口的类型改成char*而不是char

返回的是哪个指针的地址?没想明白

#13


改成
 static char s[]="nksndl";

#14


谢谢各位的回答,我不是要一个解决方法(这个解决方法自己也可以想到),而是出现乱码的原因

#15


引用 14 楼 jsyooo 的回复:
谢谢各位的回答,我不是要一个解决方法(这个解决方法自己也可以想到),而是出现乱码的原因

字符数组的情况与一般的变量是不同的。
比如:
int a(void)
{
int s=1;
return s;
}
main()
{
int b; 
p=a();
printf("%d\n",p);
}这样的代码没有问题,因为在return s时,会产生一个临时的变量将s的值复制进去,然后给b。
但是问题在于你的代码中return s;时,s是数组名,其实只是一个地址,复制时也只会复制这个地址,并不会将整个数组的内容都复制下来,所以main中的char *p得到的只是一个地址,而局部变量在函数结束之后就会被收回,所以这个地址已经是无效的了。
你上面的代码有可以是乱码,有可能不是乱码,取决于这块已经被收回的地址的内容有没有被写入新的内容,这个基本上是随机的。

#16


p=a();
程序运行到这里时,p里面的确就是"nksndl",虽然临时变量被释放掉了,但只要内存没有被重新写入,则会一直保留,当你执行如下语句的时候:
printf("%s\n",p);
注意,printf是一个函数,一进入这个函数的时候,会申请一些变量(可以调试进去看),这些申请的变量将写入原来"nksndl"所占的内存,所以是乱码(因为被重写了);

当你执行如下语句的时候:
printf("%c\n",*p);
由于*p是在调用printf函数之前运算的,也就是说,先计算*p,得到一个字符,然后将这个字符传入printf函数,而这个字符可是按值传递的,所以到了printf函数里面,就算"nksndl"被重写,已经不影响到输入的值了,这个输入的值(就是字符n)已经与内存地址p没有关系了,相当于:
p=a();
char c = *p;
printf("%c\n", c);

#17


引用 14 楼 jsyooo 的回复:
谢谢各位的回答,我不是要一个解决方法(这个解决方法自己也可以想到),而是出现乱码的原因

指向已经释放了的内存空间,值已经是不可预料的了,出现了乱码有什么奇怪?

#18


引用 16 楼 yang79tao 的回复:
p=a();
程序运行到这里时,p里面的确就是"nksndl",虽然临时变量被释放掉了,但只要内存没有被重新写入,则会一直保留,当你执行如下语句的时候:
printf("%s\n",p);
注意,printf是一个函数,一进入这个函数的时候,会申请一些变量(可以调试进去看),这些申请的变量将写入原来"nksndl"所占的内存,所以是乱码(因为被重写了);

当你执行如下语句的时候:
p……



仔细看了你的回答,感觉有点明白了,但是我还试了试用for循环 依次执行printf(“c%”,*p++);也能输出整个字符串,难道在这个过程当中前面一次的printf函数的执行没有修改掉字符串的值?

#19



char* fun()
{
char buff[] = "123456";
return buff;
}

char* p = fun();
int n = strlen(p);
for (i = 0; i < n; ++i)
{
printf("%c\n", *p++);
}


是这样吗?只有第一个不是乱码,后面的都是乱码。你的代码怎样?注意,如果你这样:
printf("%c %c %c\n", *p, *(p + 1), *(p + 2));
打出来的,都是正常的字符,原因我在上一贴已经说过了。

#20


函数结束时销毁栈,因此你不能返回栈上的指针,除非你new出来的

#21


看来问题已经解决了。。。。返回千万别放回指向局部变量的指针

#22


引用 19 楼 yang79tao 的回复:
C/C++ code

char* fun()
{
    char buff[] = "123456";
    return buff;
}

char* p = fun();
int n = strlen(p);
for (i = 0; i < n; ++i)
{
    printf("%c\n", *p++);
}



是这样吗?只有第一个不是乱码,后……
当然是这样,我也不至于那么笨,呵呵

#23


这就是所谓的野指针,该内存地址的内容已经被系统回收,其内容具有不确定性。

#24


把你的完整代码贴上来,无论是理论上,还是我自己实际操作,都是乱码(只有第一个字符是正常的)。

#25


引用 24 楼 yang79tao 的回复:
把你的完整代码贴上来,无论是理论上,还是我自己实际操作,都是乱码(只有第一个字符是正常的)。

以前的代码弄丢立刻,现在重新写了一个,确实是乱码,可能我以前程序哪里弄错了,现在明白了,谢谢你的回答。