当前位置:   article > 正文

C语言·指针_指针取值

指针取值

目录

指针的含义

指针初始化

使用指针

二级指针以及二级指针的传递

指针与一维数组

字符指针与字符数组的初始化

指针与动态内存申请

指针和自增自减运算符


指针的含义

1、按变量地址存取变量值的方式称为“直接访问”,如printf("%d",i);scanf("%d",&d);

另一种存取变量的方式称为“间接访问”,将变量i的地址存放到另一个变量中。

在C语言里,指针变量是一种特殊的变量,它用来存放变量的地址。

即指针存放的是地址,指针就是地址。

声明与初始化的格式:

基类型  *指针变量名;例如:int* i_pointer;

//*符号是用来说明这是指针变量的,指针变量名为i_pointer,不是*i_pointer。

指针变量与指针是两个不同的概念。设P是一个指针变量,则P的值是一个指针。指针就是地址,指针变量就是存储地址的变量用指针变量p存储变量i的地址,平时说p指向i。

类型名是int*,所以以后要把*和int写在一起,而不是后面的指针变量名。

2、指针常量                                                                                                                                                        const int *p;  是声明一个"常整数"指针,会对*p进行保护,试图改变*p是编译器会检查的一种错误,但是可以改变p(不可以改变*p,可以改变p)。

int  * const  p;是保护p的,此时不可以修改p,可以修改*p。

指针初始化

        声明指针变量只是为指针留出空间,但是并没有把它指向对象。所以在使用前,初始化p是至关变量的。

初始化方法一:使用&运算符把某个变量的地址赋给它

int i,*p;

p=&a;

初始化方法二:在声明指针变量的同时对它进行初始化

int i;

int  *p =&i;

初始化方法三:把i的声明和p的声明合并,但是需要首先声明i;

int i, *p=&i;

注意:只有在声明的同时对指针进行初始化时,才会有*p = &i;其余时候,都是p=&i;在对指针进行声明时,"*"是用来向编译器指明p的类型的,而不是作为间接寻址运算符。​​​​​​​

​​​​​​​ &和*:

&:取地址操作符,也叫引用(只有在scanf函数里面&是取地址操作,其余情况下,都是引用)。通过该操作符我们可以获取一个变量的地址值。

*:取值操作符,通过该操作符我们可以得到一个地址对应的数据,即根据地址得到该地址里存储的内容。

&i就是i在内存中的地址,p=&i,*p=i。也就是说,&i=i的地址,*p=i的值

只要p指向i,*p就是i的别名。*p不仅拥有和i相同的值,而且对*p的改变也会改变i的值。

在函数体内*p每次出现都将是对x的间接引用。

注意:这是错误的:

  1. float a;
  2. int *pointer_1;
  3. pointer_1=&a;
  4. /*
  5. 出错原因:只有整型变量的地址才能放到整型变量的指针变量中,
  6. 定义了指针变量的类型,那么就只能存放该类型的变量
  7. */
  8. int *a,b,c;//出错原因:不知道是三个指针变量还是一个指针变量。
  9. int *a,*b,*c;//这是正确的

这里&*pointer_1 与 &a 相同,都表示a的地址,即pointer_1.
//&*pointer_1 先执行*pointer_1 来存储A的地址,*pointer_1=a,再&,则会获取a的地址。

*&a会先运行&a,得到a的地址,再进行*运算,则会得到变量a,即显示变量a的内容。

按值运算和按地址运算:

在C语言里,若是对值操作,让一个变量的值赋给另一个变量,就会临时生成一个临时地址,接下来就只是对临时地址操作,这时候两个变量还是两个不同的地址。例如,定义i=5,j=i;则此时对j进行操作,j的值会改变,但是i的值不改变,因为j没有指向i的地址,两者不是同一个地址。

但在操作时有*或&操作符,则是对地址进行操作,此时一个变量赋值给另一个变量,是对同一个地址进行不同的操作,两个变量指向同一个地址。

有关引用的使用方法的实例:

  1. /*找出数组中的最大元素和最小元素*/
  2. #include <stdio.h>
  3. #define N 10
  4. void max_min(int a[],int n,int *max, int *min);//函数原型
  5. int main()
  6. {
  7. int b[N],i,big,small;
  8. printf("Enter %d numbers: ",N);
  9. for ( i = 0; i < N; i++)
  10. {
  11. scanf("%d",&b[i]);
  12. }
  13. max_min(b, N, &big, &small);//调用函数max_min
  14. /*
  15. 调用max_min函数时,将传递两个指向变量的指;然后max_min函数把答案存储在这些变量中
  16. b是整型数组,N是元素的个数,big和small是普通的整型变量。
  17. 当max_min函数找到数组b中的最大元素时,通过给*max赋值的方法把值存储在big中。
  18. max = &big
  19. */
  20. printf("Largest: %d\n",big);
  21. printf("Smallest: %d\n",small);
  22. return 0;
  23. }
  24. void max_min(int a[], int n, int *max, int *min)
  25. {
  26. int i;
  27. *max = *min = a[0];
  28. for ( i = 1; i < n; i++)
  29. {
  30. if (a[i]> *max)
  31. {
  32. *max=a[i];
  33. }
  34. else if (a[i]< *min)
  35. {
  36. *min = a[i];
  37. }
  38. }
  39. }

输出结果:

Enter 10 numbers: 34 82 49 102 7 94 23 11 50 31
Largest: 102
Smallest: 7

使用指针

在int i,*p=i;的情况下:

1.        printf("%d\n",*p);//输出i的值

2.        *p=2;//等同于i=2;

3.        q=p;//把p的内容(即i的地址)复制给q,p和q同时指向i;注意:这里没加"*"符号。

4.        *q=*p;//假如指向j,那么这条语句就是将i的值复制给j。

5.         &a[i]是指向a中元素i的指针。

二级指针以及二级指针的传递

二级指针也是一种指针,只服务于一级指针的传递与偏移。

指针与一维数组

思考:为什么在数组那一篇文章里,一维数组在函数调用进行传递时,它的长度子函数无法知道呢?这是由于一维数组名中存储的是数组的首地址。数组名c中存储的地址是0x0015faaf4,所以子函数change中其实传入了数组的地址,不知道数组有多长。

指针法:定义一个指针变量时,指针变量的类型要和数组类型保持一致,通过取值操作,就可将“h”改成"H"。

下标法:获取数组元素时,也可以通过取下标的方式来获取数组元素并进行修改。

字符指针与字符数组的初始化

字符指针可以初始化赋值一个字符串,字符数组初始化也可以赋值给一个字符串。

例如:char *p="hello",是把字符串常量"hello"的首地址赋给P。char c[10]= "hello'"等同于strcpy("hello");

指针与动态内存申请

如果数据存储在栈空间中,那么栈的大小在编译时是确定的。如果使用的空间大小不确定,那么久要使用堆空间。

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. int main()
  5. {
  6. int i;
  7. char *p;
  8. scanf("%d",&i);//输入要申请的空间的大小
  9. p=(char*)malloc(i);//使用malloc动态申请堆空间
  10. strcpy(p,"malloc success");
  11. puts(p);
  12. free(p);//free时必须使用malloc申请时返回的指针值,不能进行任何偏移
  13. printf("free success\n");
  14. return 0;
  15. }
  1. #include <stdio.h>
  2. int main()
  3. {
  4. char *p = "hello" ;//把字符串常量“hello"的首地址赋给p
  5. char c[10]="hello";//等价于strcpy(c,"hello");
  6. printf("c[0]=%c\n",c[0]);
  7. printf("p[0]=%c\n",p[0]);
  8. c[0]='H';
  9. p[0]='H';//加上这一句会显示错误,因为不可以对常量区数据进行修改。
  10. return 0;
  11. }
  12. /**
  13. * @brief
  14. * 如果不加c[0]='H';p[0]='H';这两句的话,会输出:c[0]=h,p[0]=h
  15. * 只加上c[0]='H';这一句话,会输出c[0]=H,p[0]=h
  16. * 但是,如果c[0]='H';p[0]='H'两句都加上,会显示错误。
  17. */

也就是说,p里面存储的是’h'的地址,当‘hello’被赋值给p后,hello就变成了一个字符串常量,如果内存存储的是字符串常量,那么这里的权限就是可读不可写。所以p[0]='H‘;会报错。

而char c[0]="hello"这一步,并不是直接c直接指向"hello"常量,而是,hello+\0都存储在栈空间里,然后复制一份给c,所以c[0]='H'后,我们会发现存储"hello"的栈里的数据变成了"Hello",而c的地址里的数据还是"hello"。我们可以对栈空间里的数据是可读可写的。

但是,如果增加的两句是p="world";c="world";那么这里面非法的是c="world",此时c不是一个变量,不可以重新赋值。p="world"这一句是将原来指向"hello"的p指针指向了"world"。也就是说,不可以指针里的常量进行修改,但是可以改变指针指向。

指针和自增自减运算符

指针与自增自减结合,不是简单的像其它的变量值一样,直接加一,而是找到下一个地址。例如:在下面的例子里,p存储了a数组的所有的数据的地址,如果此时输出*p,p会指向a数组的开始数据,即a[0],执行p++ ,p就会指向下一地址即a[1].

当然*p ++会先执行*p,再执行p++。

  1. include<stdio.h>
  2. //指针与自增自减
  3. //只有比后增优先级高的 操作符,才会作为一个整体,如().
  4. int main()
  5. {
  6. int a[3]={2,5,4};
  7. int *p;
  8. int j;
  9. p = a;
  10. j = *p++;//先把*p的值赋给j,然后对p加一
  11. printf("a[0] =%d, j=%d,*p=%d\n",a[0],j,*p);
  12. return 0;
  13. }
  14. /**
  15. * @brief
  16. * 因为 p = a,那么p是A的地址
  17. * a[0] = 2, p为a[0]的地址,j =*p ,则j输出a[0]
  18. * 然后执行p = p+1;则 *p输出的是a[1]的数值。
  19. */

通过上面的消息也可以看出:输出*p输出的是p地址里存储的数据。

  1. include<stdio.h>
  2. //指针与自增自减·升级一下
  3. //只有比后增优先级高的操作符,才会作为一个整体,如().
  4. int main()
  5. {
  6. int a[3]={2,5,4};
  7. int *p;
  8. int j;
  9. p = a;
  10. j = *p++;//先把*p的值赋给j,然后对p加一
  11. printf("a[0] =%d, j=%d,*p=%d\n",a[0],j,*p);
  12. printf("p[1]=%d\n",p[1]);
  13. j = p[0]++;//先把p[0]赋给j,然后对p[0]加1
  14. printf("a[0]=%d,j=%d,*p=%d\n",a[0],j,*p);
  15. return 0;
  16. return 0;
  17. }
  18. /**
  19. * 因为上面的例子里,执行了p++,所以,这里p[0]=a[1]
  20. * 输出结果:
  21. * a[0]=2,j=2,*p=7
  22. * p[1]=8
  23. * a[0]=2,j=7,*p=8
  24. *
  25. */
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/sysmno/article/detail/63185
推荐阅读
相关标签
  

闽ICP备14008679号