指针专题一
1.指针的基本用法
掌握指针的基本用法,我学习了很久的指针了,还是不理解,可以想一下为啥还是不理解。
自己并没有那种非常的专注的去学习,最重要的是学习之后,没有进行,总结思考。
c程序设计使用指针可以:
- 使程序简洁、紧凑、高效
- 有效的表达复杂的数据结构
- 动态的分配内存
- 得到多于一个的函数返回值
1.1 常见的指针名词:
地址: 在计算机内存中,最小的单位是字节。每一个字节(单元),都有一个编号,称为地址。
指针: 在C语言当中,内存单元的地址称为指针。
指针变量:专门用来存放地址的变量,称为指针变量(也叫做地址变量)。
补充理解:
-
内存是以字节(1BYTE==8BIT)8位 作为最小的单位的。
就像一栋楼是以一个房间为最小单位的。比如快递员送快递,送到63栋2单元602 一样,送到602这个门里面。602被认为最小单元,而不是哪一间屋子。(主要是考虑到使用的价值) -
所说的变量的地址,一般的说的是首地址,(起始地址,地址是连续的。)
在不影响理解的情况中,有时对地址、指针和指针变量不区分,统称为指针。 -
再重复一次概念:在内存中每一块内存都有它的编号,(这个编号叫地址,请分清地址和内存的区别,)这个编号叫做指针(如上,内存单元的地址称为指针。)
1.2 指针
指针变量的说明:
一般形式如下:
<存储类型> <数据类型> * <指针变量名>
例如普通变量:
auto int m;
指针变量:
auto int * P; 指针的英语 pointer
说明:
指针指向的内存区域中的数据称为指针目标,
如果他指向的区域是程序中的一个变量的内存空间,则这个变量称为指针的目标变量,简称为指针的目标。
如上面图片,我定义了一个变量
double x =-126;
int *px;
px=&x;
那么X的数值本来就是 x= -126; &x是变量x在内存中的起始地址, (&x)就是 地址取 ,也是X的数据,
要想获得指针的目标,给他加上*,,也即是 px。。这里的 * 和 int * 的 “ * ” 不是一个意思,int * 是定义了指针的类型。 单纯的 * 是指我通过 我就可以找到我的指针的目标。通过 * 我就可以找到指针指向的地址里面的数值。
1 #include <stdio.h>
2 #include <stdlib.h>
3
4
5 int main(int argc, const char *argv[])
6 {
7 int a=1314;
8 int * p=NULL;
9 p=&a;
10
11 printf("a=%d,&a=%p,*(&a)=%d\n",a,&a,*(&a));
12 printf("p=%p,*p=%d,sizeof(p)=%ld,sizeof(*p)%ld\n",p,*p,sizeof(p),sizeof(*p))
13
14 return 0;
15 }
~
linux@ubuntu:~/everyday/2020-8-3/poninter_1$ ./test
a=1314,&a=0x7ffff96aa1dc,*(&a)=1314
p=0x7ffff96aa1dc,*p=1314,sizeof(p)=8,sizeof(*p)4
特别注意:引入指针要注意程序中的 PX 、 *PX 、 &PX三者所代表的意思。
1. PX----指针变量,他的内容是指向的变量的地址
2. *px ----指针所指向的目标,他的内容是数据
3. &px ----指针变量的地址,(指针变量占用的存储区域的地址,是个常量)
指针变量自身也是有地址的,(比如快递员自己也会取网购啊)
指针的赋值运算指的是指:通过赋值运算符向指针变量送一个地址数值。
向一个指针变量赋值的时候,送的值必须是地址常量或者指针变量。不能是普通的整数(0除外)。
指着赋值运算,常见的有以下的几种形式。
-
把一个普通变量的地址赋值给具有相同数据类型的指针
double x=3.14 ,*p;
p=&x; -
把一个已经有了地址值的指针,赋值给具有相同类型的另外的一个指针变量。
float x ,* px,* py;
px =&x;
py=px; -
把一个数组的地址赋值给具有相同数据类型的指针。例如:
int a[20],*pa;
pa=a; //他是等价于 pa =&a[0]的。
总结与思考:
主要介绍指针相关的内容,包括指针的概念、理解、指针变量的说明和赋初值。
什么是指针:
内存以字节为最小单位,进行划分,字节的编号,叫做地址,在C语言中,内存的地址就叫做指针。
专门存放地址的变量,就叫做指针变量。也简称指针。
我调了一个代码,但是对指针占多少字节并不是清楚的, 4字节? 8字节??
需要看计算机的操作系统是啥。
2.指针的运算
1. 指针运算是以指针变量所存放的地址量作为运算量而进行的运算。
2. 指针运算的实质就是地址的计算。
3. 指针运算的种类是有限的,他只能够进行赋值运算,算数运算和关系运算。
2.1指针的算数运算 :
(+ px+n : 指针向地址大的地方移动n个字节)
(- px-n : 指针向地址小的地方移动n个数据)
(++ px++ : 指针向地址大的方向移动一个数据)
(-- px-- :指针向地址小的方向移动一个数据)
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 int a=10,*p;
6 double b=3,*q;
7 p=&a;
8 q=&b;
9
10 printf("%p %p\n",p,p+2);
11 printf("%p %p\n",q,q+2);
12
13 return 0;
14 }
~
linux@ubuntu:~/everyday/2020-8-3/poninter_2$ ./a.out
0x7ffcb00b64cc 0x7ffcb00b64d4
0x7ffcb00b64d0 0x7ffcb00b64e0
以上是一个运算 注意:
第一 int 占四个字节
第二 指针指向的是首地址,
第三 不同的数据类型的两个指针实行加减整数的运算是无意义的。
第四 px+n表示的实际位置的地址量是: (px)+sizeof(px的类型)*n
指针做运算的意义是什么?
两个指针相减运算:
- px- py 运算的结果是两指针指向的地址位置之间相隔数据的个数。两指针相减不是两指针持有的地址值相减的结果。
- 两指针相减的结果值不是地址量,而是一个整数值,表示两个指针之间相隔数据的个数。
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 int a1=10,*p;
6 double b=3,*q;
7 p=&a1;
8 q=&b;
9
10 int a[5]={1,2,3,4,5};
11 int *px,*py;
12 px=a; //px=&a[0]
13 py=&a[3];
14
15 printf("%p %p\n",p,p+2);
16 printf("%p %p\n",q,q+2);
17
18 printf("%p %p\n",px,py);
19 printf("%d %d\n",*px,*py);
20 printf("%d\n",py-px);
21
22 return 0;
23 }
~
linux@ubuntu:~/everyday/2020-8-3/poninter_2$ ./a.out
0x7ffe1bbd6924 0x7ffe1bbd692c
0x7ffe1bbd6928 0x7ffe1bbd6938
0x7ffe1bbd6950 0x7ffe1bbd695c
1 4
3
2.2指针运算符:
2.3指针关系运算:
- 两个指针之间的关系运算表示他们指向的地址位置之间的关系,指向地址大的指针大于指向地址小的指针。
- 指针与一般的整数变量之间的比较没有意义,但是可以和0进行等或者不等的关系运算,判断指针是否为空。
1 #include <stdio.h>
4 int main(int argc, const char *argv[])
5 {
7 int a[]={5,6,7,8,9,10};
8 int *p=&a[1],y;
10 y= (*--p)++;
11 printf("y==%d\n",y);
12 printf("a[0]==%d\n",a[0]);
14 return 0;
15 }
linux@ubuntu:~/everyday/2020-8-3/poninter_3$ ./a.out
y==5
a[0]==6
这个是一个很好的例子。
程序举例中:注意指针当前的值。
1 #include <stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5 int i ,*p,a[7];
6 p=a;
7 for(i=0;i<7;i++)
8 {
9 scanf("%d",p++);
10 printf(" ");
11 }
12 p=a;
13 for (i=0;i<7;i++)
14 {
15 printf("%d",*p);
16 printf(" ");
17 p++;
18 }
19
20 return 0;
21 }
22
23
linux@ubuntu:~/everyday/2020-8-3/poninter_4$ ./a.out
44
45
45
47
48
49
45
44 45 45 47 48 49 45 linux@ubuntu:~/everyday/2020-8-3/poninter_4$
这是一个很有意思的例子,要时刻注意指针指向的位置,不然就会出现指针在自加的时候出现越界。
思考:
- 注意指针在移动的过程当中,要注意指针是否会越界。要注意指针当前的值,需不需要做修正。
- 指针运算的本质:对地址的运算
- 指针+1移动多少个字节? 移动n个目标数据类型。
3.指针与数组
- 指针与数组(指针去访问数组,去遍历数组)
指针与数组
-
在C语言中,数组的指针是指数组在内存中的起始地址,数组元素的地址指数组元素在内存中的起始地址。
-
一维数组的数组名为一维数组的指针(起始地址)
例如:double x[8];
因此,x为x数组的起始地址。
设指针变量 px的地址值等于数组指针x(也即是指针变量PX指向数组的首元素)
则:
x[i] *(px+i) *(x+i) px[i]
这四种具有完全相同的功能,
貌似形式上相同的 x[i]和px[i],其实并不相同,一个是常量(x[i]),一个是变量px[i]。
px[i] ======*(px+i);
1 #include<stdio.h>
2
3 int main(int argc, const char *argv[])
4 {
5
6 int a[]={1,2,2,3,5,9,7,99};
7 int *p ,i,n;
8 p=a;
9 n=sizeof(a)/sizeof(int);
10 for(i=0;i<n;i++)
11 {
12 printf("%d %d %d %d",a[i],*(p+i),*(a+i),p[i]);
13 printf("\n");
14 }
15
16 printf("\n");
17 printf("%p %p %p ",a,a+1,a+2);
18 printf("%p",&a[0]);
19
20 printf("\n");
21 printf("a[3]==%d",a[3]);
22 printf("\n");
23
24 printf("*(p+3)==%d",*(p+3));
25 printf("\n");
26
27 // a++;
28 p++;
29
30
31 return 0;
32 }
~
~
~
~
linux@ubuntu:~/everyday/2020-8-3/poninter_5$ ./a.out
1 1 1 1
2 2 2 2
2 2 2 2
3 3 3 3
5 5 5 5
9 9 9 9
7 7 7 7
99 99 99 99
0x7ffe579ed6b0 0x7ffe579ed6b4 0x7ffe579ed6b8 0x7ffe579ed6b0
a[3]==3
*(p+3)==3
程序举例:
编写一个函数,将整形数组中 n 个数按照反序存放。
1 /* 编写时间:2020-8-3
2 * 编写一个函数,将整形数组中 n 个数按照反序存放。
3 * 使用指针的形式。
4 *
5 */
6
7 #include <stdio.h>
8 #define N 10
9
10 int main(int argc, const char *argv[])
11 {
12 int a[N]={1,2,3,4,5,6,7,8,9,10};
13 int *p ,*q;
14
15 p=a;
16 q=&a[N-1];
17
18 while(p<q)
19 {
20
21 int t=*p;
22 *p=*q;
23 *q=t;
24 p++;
25 q--;
26 }
27
28 for(int t=0;t<N;t++)
29 {
30 printf("%d ",a[t]);
31 }
32
33 return 0;
34 }
~
linux@ubuntu:~/everyday/2020-8-3/poninter_6$ ./a.out
10 9 8 7 6 5 4 3 2 1 linux@ubuntu:~/everyday/2020-8-3/poninter_6$