首页 > 代码库 > 指针的一些问题

指针的一些问题

1、c++/c语言中不少地方,数组和指针可以相互替换使用,容易让人产生一种错觉,指针和数组是等价的。

数组要么在静态存储区域创建,如全局数组;要么在栈上创建如函数内的数组。数组的名称对应着(而不是指向)一块内存,它的地址和容量在其生命周期内保持不变,数组的内容可变。

指针可以指向任意类型的内存块,它的特征是可变的,所以常常用指针来操作动态内存,指针比数组灵活,当时容易出错。

char a[] = "hello";a[0] = x;cout<<a<<endl;char *p = "world";  //这里的p指向的是常量字符串p[0] = x;  //编译器不能发现该错误cout<<p;

如上边一段代码,a是容量为6的字符数组,a中的内容是可以改变的,如a[0]=‘x‘。指针p指向的是一个常量字符串“world”(位于静态存储区),常量字符串的内容是不能够被修改的。但是从语法的角度看,编译器并不知道p[0]=‘x‘有什么问题,但是该语句在企图执行时,就会出错。

char a[] = "hello";char *p = "world"; cout<<sizeof(a)<<endl;             //6cout<<sizeof(p)<<endl;             //4cout<<sizeof(char *)<<endl;     // 4cout<<sizeof(void *)<<endl;      //4cout<<sizeof(int *)<<endl;        //4  cout<<sizeof(short *)<<endl;    //4

 

另外指针和数组的容量计算也是有区别的。以上一段代码为例,sizeof(a)的值为6,但是sizeof(p)的值为4,这是因为sizeof(a)可以计算出数组的字节数,但是sizeof(p)得到的是一个指针变量的字节数,相当于sizeof(char *),而不是p所指向的内存容量。c++、c语言是没有办法知道指针所指向的内存容量,除非在申请内存时记住。

 

void test(char p[100]){    cout<<sizeof(p)<<endl;//4}

 

注意:当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。如上边的代码,sizeof(p)的大小为4。

2、指针参数传递内存

void GetMemory(char *p){    p = (char *)malloc(100);}int main(){      char *str = NULL;      GetMemory(str);      strcpy(str,"hello");      printf("%s",str);   //运行出错      free(str);}

这段代码运行出错,原因出自函数Getmemory中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是_p,编译器使_p=p。如果函数体内的程序修改了_p的内容,就导致了参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。但是在本例中,_p申请了新的内存,只是把_p所指向的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西,每次执行一次GetMemory就会泄露一块内存。因为没有执行free释放内存。

void GetMemory2(char **p,int num){    *p = (char *)malloc(num);}

如果一定要使用指针参数去申请内存,那么可以使用指向指针的指针,如上边的代码。当然也可以使用函数返回值来传递动态内存,如:

char *GetMemory3(int num){    char *p = (char *)malloc(num);    return p;  }

但是值得注意的是,我们这里使用返回值返回的是动态分配的堆内存,不是栈内存,如果不小心返回的是栈内存,就会出错,因为在函数结束时,栈内存自动消亡了。

char *GetMemory4(){    char p[] ="hello world!"    return p;   //编译器会发出警告  }

对上边的程序稍作修改

char *GetMemory5(){    char *p ="hello world!"    return p;   }

这时候p指向的是字符串常量,位于静态存储区,生命周期恒定不变,那么此时返回的是一个只读的内存块。