指针
指针的计算机底层逻辑
当一个程序被启动的时候,操作系统将会做下面几件事情:
- 把程序的内容(代码段、数据段)从硬盘复制到内存中;
- 创建一个数据结构PCB(进程控制块),来描述这个程序的各种信息(例如:使用的资源,打开的文件描述符...);
- 在代码段中定位到入口函数的地址,让CPU从这个地址开始执行。 操作系统通过地址来管理内存。
在一般情况下,我们通过变量名对变量进行使用,不过变量名只是一个抽象的概念,在编辑时,编辑器会将其转换为该变量在内存中的地址。
而通过指针,即可直接访问地址。
- 指针变量首先是一个变量,所以它拥有变量的所有属性:类型和值。它的类型就是指针,它的值是其他变量的地址。 既然是一个变量,那么在内存中就需要为这个变量分配一个存储空间。在这个存储空间中,存放着其他变量的地址。
- 指针变量所指向的数据类型,这是在定义指针变量的时候就确定的。例如:int *p; 意味着指针指向的是一个int型的数据。
指针的简单用法
数组指针
一维数组与指针
int *p,a[10]; //定义一个指向整型的指针和一个一维数组
一维数组中,数组名a相当于数组首元素 a[0] 的地址,即 a 等价于 &a[0]。
数组元素的访问方式:
- 直接访问:数组名[下标],如a[3].
- 间接访问:*(数组名 + i),表示a[i]
- 间接访问:(指针变量)当将数组的地址赋给指针变量P时,如 p = a;
将数组a的首地址赋给p之后,可以通过p的加减遍历数组元素,(p+i) = a[i];
二维数组与指针
用如下的程序判断指针如何指向二维数组
#include<stdio.h>
#define M 3
#define N 4
int main (void)
{
int *p,a[M][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
p=&a[0][0];
printf("The address of different rows:\n");
printf ("a + 0 = %p\n",a);
printf ("a + 1 = %p\n",a + 1);
printf ("a + 2 = %p\n\n",a + 2);
printf("The same address:\n");
printf ("a[2] + 1 = %p\n",a[2] + 1);
printf ("*(a+2) +1 = %p\n",*(a + 2)+1);
printf ("&a[2][1] = %p\n\n",&a[2][1]);
printf("The same element:\n");
printf ("*(a[1] + 3) = %d\n",*(a[1] + 3));
printf ("*(*(a + 1) + 3) = %d\n",*(*(a + 1)+3));
printf ("a[1][3] = %d\n", a[1][3]);
return 0;
}
从上面的程序我们可以看出,二维数组的存储结构为顺序存储,
- i行的首元素地址:a[1]+0<-->* (a + i) +0 <--> &a[i][0]
- i行的1列元素地址:a[1]+1<-->* (a + i) +1 <--> &a[i][1]
- i行的2列元素地址:a[1]+2<-->* (a + i) +2 <--> &a[i][2]
- i行的j列元素地址:a[1]+j<-->* (a + i) +j <--> &a[i][j]
通过访问符‘*’, 二维数组a[i][j]有以下几种方法
*(a[i] + j) <--> *(*(a + i) + j) <-->*&a[i][j]<-->a[i][j]
注意:二维数组中,虽然i行首地址和首元素的地址数值上相同,但其的性质不相同,首地址加一变为下一行的首地址,而首元素的地址加一变为下一个元素的地址
指针数组
定义的一般形式
int *a[n];
由于[]的优先级高于*,a[n]表示a是一个数组,类型为int *
#include <stdio.h>
int main(){
int a = 16, b = 932, c = 100;//定义一个指针数组
int *arr[3] = {&a, &b, &c};//也可以不指定长度,直接写作 int *arr[]
//定义一个指向指针数组的指针
int **parr = arr;
printf("%d, %d, %d\n", *arr[0], *arr[1], *arr[2]);
printf("%d, %d, %d\n", **(parr+0), **(parr+1), **(parr+2));
return 0;
}
指针和字符串
一般形式:
char *str = "I love China!"
表示将字符串“I love China!”的地址给str
可以用 &str输出
其他用法
指向结构体
指向函数
·····
指针的简单操作
可以在子函数中改变主函数中的值
如上次的2000题
#include <stdio.h>
void swap(char*p1,char*p2);
int main(void)
{
char c1,c2,c3,c;
char*p1,*p2,*p3;
scanf("%c%c%c",&c1,&c2,&c3);
swap(&c1,&c2);
swap(&c1,&c3);
swap(&c2,&c3);
printf("%c %c %c",c1,c2,c3);
}
void swap(char*p1,char*p2)
{
char c;
if(*p1>*p2){
c = *p2;
*p2 = *p1;
*p1 = c;
}
}
我在swap函数中用指针改变其指向的值(主函数中),从而达到判断大小,交换值的目的
指针指向类型和指针类型的区别
指针的类型是指针自身的类型,而指针所指向的类型是指针指向的数据(内存)的类型。
课后习题
10.12.1
#include <stdio.h>
int main(void)
{
int ref[] = { 8,4,0,2};
int *ptr;
int index;
for(index = 0,ptr = ref;index < 4;index++,ptr++)
printf("%d %d\n",ref[index],*ptr);
return 0;
}
运行结果
10.12.2
ref 有4个元素
10.12.3
ref地址是ref[0]的地址,ref + 1表示 ref[1]的地址,ref为数组名,不能自增,无指向
10.12.4
a.
- ptr 值是12
- (ptr + 2)的值为16 b.
- ptr 值是12
- (ptr + 2)的值为1
10.12.5
a.
**ptr的值为12
**(ptr+1)为16
b.
**ptr的值为12
**(ptr+1)为14