char数组和char指针应该注意的

xiaoxiao2021-02-28  70

数组要么在静态区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命周期内保持不变,只有数组的内容可以改变。

指针可以随时指向其他类型的内存块,它的特征是“可变”,所以常用指针来操纵动态内存。指针远比数组灵活,但也更危险。

 

1.返回指向栈上的内存的指针

char * testStr1(){ char value[4] = "hello"; return value; } void main(){ char *str = NULL; str = testStr1();//str的内容是垃圾 cout<<str<<endl; }

 

有问题,value的内存位于栈上,该内存在函数体结束时被自动销毁。所以,return语句不可返回指向“栈内存”的“指针”或“引用”。

但为什么以下两种形式可以呢? 

//1.返回int形栈上内存 int fun1() { int j = 3; return j; } //类 Complex //2.返回类(栈内存) Complex fun2() { Complex c; return c; }

1)对于返回int型的栈上内存的解释:return返回值的机制为:将返回值存入eax寄存器中,然后系统再将eax中的值赋给变量(i)。

2)对于返回值是类类型的解释:返回值是对象时会调用拷贝构造函数。因为返回的局部变量在函数结束时已被销毁,所以编译器都会先建立一个此对象的临时拷贝,而在建立该临时拷贝时就会调用类的拷贝构造函数。

3)对于返回指向栈存储的“指针”的解释:

在执行return语句时,首先将return后面的地址值返回存入到比如eax寄存器中,然后系统再将eax中的地址值给接收函数返回地址的指针变量。这看起来都没什么问题,但问题在于两个方面:

[1]接收函数返回地址值的指针变量要访问此地址中的内容。

[2]子函数运行结束后,一切有关于局部变量的内存都已经释放回收。那么在用这个地址来操作就很危险:地址中没有内容

++++++++++++++++++++++++++++++++++++=

总结:

(1)return

不管是返回指针还是返回值,return将return之后的值存到eax寄存器中,回到父函数再将返回的值赋给变量。

(2)局部地址

在函数内返回一个指针会出错的原因:子函数运行完毕时,存局部变量的所有栈地址的内容已经被释放。若在父函数中再访问这些地址中的内容时,因为这些地址的内容已经被释放,所访问到的值可能是乱的、不定的。

参考:

1)http://www.cnblogs.com/wgang171412/p/5019148.htm return机制

2)https://blog.csdn.net/jmh1996/article/details/78384083 c/c++return如何实现的?return的内部机制

 

 

 

2.返回静态内存

char * testStr2(){ char * value = "hello"; return value; } void main(){ char *str = NULL; str = testStr1(); cout<<str<<endl; }

 

没问题,不会出错。只不过testStr2的设计概念是错的。因为testStr2内的字符串“hello”是常量字符串,位于静态存储区,它在程序生命周期内恒定不变,不允许改变。无论什么时候调用testStr2,它的返回值始终是同一个“只读”的内存块。

3.不能对空指针进行strcpy操作

char *testStr3(){ char *value1 ="str"; char *value2 = NULL; strcpy(value2 , value1); return value2; }

 

有问题,value2是空指针,没有分配内存。

 

 

4.参数为指针时,形参指向静态内存或者另一地址,实参实际上无任何变化

buf依然是空的,因为参数传递相当于是char *value = buf,value指向buf

而value = "hello",相当于是value指针指向了hello所在的静态内存,但是buf的内容没变

void testStr4(char * value){ value = "hello"; } void main(){ char buf[16]={0}; testStr4(buf); }

 

5.buf最后是hello,参数传递,此时,value 和buf指向的是同一块内存,strcpy是将value1中的内容复制到value所指的内存中

返回时由于value和bufs还是指向同一块内存的,所以bufs的内容为hello.

void testStr5(char *value){ char *value1 = "hello"; strcpy(value, value1); } void main(){ char buf[16]={0}; testStr4(buf); }

 

4和5要对比着看

6.如果函数的参数是一个指针,不要指望该指针去申请动态内存

void testStr6(char *p, int num){ p = (char* )malloc(sizeof(char) * num); } void main(){ char *str = NULL; testStr6(str, 100); //str仍为NULL strcpy(str, "hello");//运行错误 }

 

结合着4和3看。只是把p的内存地址变了,str丝毫未变。且每调用一次就会造成一次内存泄露,因为没有调用free释放内存。

如果非要用指针参数去申请内存,那么久应该该用“指向指针的指针”

void testStr7(char **p, int num){ *p = (char* )malloc(sizeof(char) * num); } void main(){ char *str = NULL; testStr6(&str, 100); //注意参数是&str,而不是str strcpy(str, "hello"); cout<<str<<endl; free(str); }

 

由于“指向指针的指针“这个概念不容易理解,可以用函数返回值来传递动态内存。

char * testStr8(int num){ char *p = (char* )malloc(sizeof(char) * num); return p; } void main(){ char *str = NULL; str = testStr8(100) strcpy(str, "hello"); cout<<str<<endl; free(str); }

 

用函数返回值来传递动态内存的方法需要特别注意一点,不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡。(参考1)

 

转载请注明原文地址: https://www.6miu.com/read-85873.html

最新回复(0)