个人对指针的通俗理解

首先我们要知道的是,

定义指针变量必须要有*,如果没有*则成了int ptr 一个普通变量

char *a=“china”;不等价于 char *a;*a=“china”

char *a=“china”; //:表示=》定义一个char类型指针a,
注意,在定义的时候赋值,这其实是做了两个工作。
等同于char *a; //定义一个指针变量
定义好的指针变量是a, 而不是*a;
所以*a=“china”; (把字符串写入a的地址)是不对的,因为char *a;本来就是一个声明,还没有赋给a对应的地址。应该为a=“china”(把字符串的地址赋给a)
*符号,在定义的语句中,表示声明了一个指针的类型,
符号,在赋值语句中,表示一个运算,取这个变量的指向内容。

char *a="abcd";

a="bcde";

先把a指向"abcd"(地址a)然后再把a指向"bcde"(地址b)

char *a="abcd";

*a="bcde";

呢?

答案是不行,编译器不会报编译错误,但是在程序运行的时候就会出错。

程序运行到*a="bcde"; 时就卡住,然后非正常退出了。

也就是我们无法通过 向*a赋值一个字符串 这种方式来改变原本存有"abcd"的那一段内存中的内容。

本质上来说,char *s定义了一个char型的指针,它只知道所指向的内存单元,并不知道这个内存单元有多大,所以:

当char *s = “hello”;后,不能使用s[0]=‘a’;语句进行赋值。这是将提示内存不能为"written"。

当用char s[]=“hello”;后,完全可以使用s[0]=‘a’;进行赋值,这是常规的数组操作。

所以

char *s = (char *)malloc(n);//其中n为要开辟空间的大小

这句话其实相当于:

char s[n];

例子

#include <stdio.h>
 
int main(int argc, char* argv[]) {
char* buf1 = "this is a test";
char buf2[] = "this is a test";
printf("size of buf1: %d\n", sizeof(buf1));
printf("size of buf2: %d\n", sizeof(buf2));
return 0;
}

结果是:

$ > ./main
size of buf1: 4
size of buf2: 15

由此我们可以知道char*和char[]的区别在于每个小单元所储存的内容一个是整体string一个是单体char,而string是常量不可被更改

什么是指针:
指针是一种特殊的数据类型,使用它可以定义指针变量,指针变量存储的是整形数据,代表了内存的编号,通过这个编号可以访问对应的内存

为什么要用指针:(必须要用才用)

  1. 函数之间是共享变量
    传参是单向值传递 全局变量容易命名冲突 使用数组麻烦、长度需要额外传递长度 虽然函数之间命名空间是独立的,但是地址空间是同一个,指针可以解决共享变量的问题

  2. 由于函数之间传参是单向的值传递(内存拷贝),对于字节数较多的变量,值传递的效率较低,如果指针传递变量的地址只需要
    4|8个字节(提高函数传参效率)

  3. 堆内存无法取名字,它不像data、bss、stack、让变量名与内存建立联系,只能使用指针记录堆内存的地址来访问对应的内存

int *ptr=array;  或int*a;  a=array

  1. int array[20]={0};  
  2. int *ptr=array;  
  3. for(i=0;i<20;i++)  
  4. {  
  5.     (*ptr)++;  
  6.     ptr++;  
  7. }  

这个例子将整型数组中各个坐标内存的值加1。由于每次循环都将指针ptr加1 个坐标,所以每次循环都能访问数组的下一个坐标

  1. char a[20];  
  2. int *ptr=(int *)a; //强制类型转换并不会改变a 的类型  
  3. ptr++;  

指针ptr被加了1,它把指针ptr 的值加上了sizeof(int),int 占4 个字节。由于地址是用字节做单位的,故ptr 所指向的地址由原来的变量a 的地址向高地址方向增加了4 个字节。由于char 类型的长度是一个字节,所以由a[0]的第四个字节到了a[4]的第四个字节。

  1. char a[20]="You_are_a_girl";  
  2. int *ptr=(int *)a;  
  3. ptr+=5;  

在这个例子中,ptr 被加上了5,编译器是这样处理的:将指针ptr 的值加上5 乘sizeof(int),在32 位程序中就是加上了5 乘4=20。由于地址的单位是字节,故现在的ptr 所指向的地址比起加5 后的ptr 所指向的地址来说,向高地址方向移动了20 个字节。

  1. #include<stdio.h>  
  2. int main()  
  3. {  
  4.     char a[20]=" You_are_a_girl";  
  5.     char *p=a;  
  6.     char **ptr=&p;  
  7.     //printf("p=%d\n",p);  
  8.     //printf("ptr=%d\n",ptr);  
  9.     //printf("*ptr=%d\n",*ptr);  
  10.     printf("**ptr=%c\n",**ptr);  
  11.     ptr++;  
  12.     //printf("ptr=%d\n",ptr);  
  13.     //printf("*ptr=%d\n",*ptr);  
  14.     printf("**ptr=%c\n",**ptr);  
  15. }  

误区一、输出答案为Y 和o
误解:ptr 是一个char 的二级指针,当执行ptr++;时,会使指针加一个sizeof(char),所以输出如上结果,这个可能只是少部分人的结果.
误区二、输出答案为Y 和a误解:ptr 指向的是一个char *类型,当执行ptr++;时,会使指针加一个sizeof(char *)(有可能会有人认为这个值为1,那就会得到误区一的答案,这个值应该是4,参考前面内容), 即&p+4; 那进行一次取值运算不就指向数组中的第五个元素了吗?那输出的结果不就是数组中第五个元素了吗?答案是否定的.
正解: ptr 的类型是char **,指向的类型是一个char *类型,该指向的地址就是p的地址(&p),当执行ptr++;时,会使指针加一个sizeof(char*),即&p+4;那*(&p+4)指向哪呢,这个你去问上帝吧,或者他会告诉你在哪?所以最后的输出会是一个随机的值,或许是一个非法操作.
总结一下:

如果 ptr++;  改为*ptr++则为正确答案,流程分析:1.char *p=a;  :由于a是一个数组,所以不需要用&a取地址,可以直接用a取地址,把a的地址赋给p,所以*p取地址内容也=Y  2. char **ptr=&p;  取p的地址赋给*ptr!!,所以*ptr,p,a其实是共用的一个地址

指针可以减指针但不可以加指针 (指针-指针)/指针类型宽度 计算两个指针间隔多少个指针元素

 char**str可以约等于char*str[]都是可以储存字符串的,str里面储存的为指针(字符串的地址),指向的为字符串,所以str的类型是char**,由此可知*str指向的是字符串内的字符,所以str+1指第二个字符串,*(str+1)指第二个字符串的第一个字符,*(*(str+1)+1)指第二个字符串的第二个字符。数组来表示就是str[1]是第二个字符串,*str[1]是第二个字符串的第一个字符,*(str[1]+1)是第二个字符串的第二个字符

指针与const

当我们为了提高传参效率而使用指针作为函数参数时 ,传参效率提高了,但是变量被共享,存在被修改的风险,可以使用const保护指针所指向的内存
const int *p; 保护指针所指向的内存不被修改
int const *p; 同上
int *const p; 保护指针变量不被修改
const int *const p; 指针变量和指针所指向内存都不能修改
int const *const p; 同上

  1. char *str[3]={  
  2.     "Hello,thisisasample!",  
  3.     "Hi,goodmorning.",  
  4.     "Helloworld"  
  5. };  
  6. char s[80];  
  7. strcpy(s,str[0]); //也可写成strcpy(s,*str);  
  8. strcpy(s,str[1]); //也可写成strcpy(s,*(str+1));  
  9. strcpy(s,str[2]); //也可写成strcpy(s,*(str+2));  

上例中,str 是一个三单元的数组,该数组的每个单元都是一个指针,这些指针各指向一个字符串。把指针数组名str 当作一个指针的话,它指向数组的第0 号单元,它的类型是char **,它指向的类型是char *。
*str 也是一个指针,它的类型是char *,它所指向的类型是char,它指向的地址是字符串"Hello,thisisasample!"的第一个字符的地址,即'H'的地址。注意:字符串相当于是一个数组,在内存中以数组的形式储存,只不过字符串是一个数组常量,内容不可改变,且只能是右值.如果看成指针的话,他即是常量指针,也是指针常量.
str+1 也是一个指针,它指向数组的第1 号单元,它的类型是char**,它指向的类型是char*。
*(str+1)也是一个指针,它的类型是char*,它所指向的类型是char,它指向"Hi,goodmorning."的第一个字符'H'

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值