一、指针
- 指针是内存中一个最小单元的编号,也就是地址
- 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
总结:指针就是地址,口语中说的指针通常指的是指针变量
地址指向该变量单元。因此,将地址形象化的称为“指针”。
意思是通过它能找到以它为地址的内存单元
指针是个变量,存放内存单元的地址(编号)
指针变量:我们可以通过&(取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中
指针是一个地址
指针变量是存放地址的变量
例如:
int main()
{
int a = 10;//在内存中开辟一块空间
int*p = &a;//对变量a,取出它的地址,可以使用&操作。
//将a的地址存放在p变量中,p就是一个指针变量,类型为int*
return 0;
}
一个内存单元是一个字节,一个字节给一个对应的地址
- 指针是用来存放地址的,地址是唯一标识一块地址空间的。
- 指针的大小在32位平台是4个字节,在64位平台是8个字节。
二、指针变量和指针类型
1.指针变量
一般形式:
类型名 *指针变量名;
引用指针变量时,可能有3种情况:
- 给指针变量赋值
例如:p=&a;
指针变量p的值是变量a的地址,p指向a
- 引用指针变量指向的变量
若以及执行p=&a;则
printf(“%d”,p);
作用是:以整数形式输出指针变量p所指向的变量a的值
若执行p=1;
表示将整数1赋给p当前所指向的变量a,即a=1
- 引用指针变量的值
printf(“%o”,p);
作用:以八进制数形式输出指针变量p的值,若p指向了a,就是输出了a的地址,即&a
运算符
- &——取地址运算符。&a是变量a的地址
- *——指针运算符(或称“间接访问”运算符),*p代表指针变量p指向的对象
2.指针类型
指针类型决定了指针进行解引用的时候,能访问的空间大小
int *p; *p能够访问4个字节
char *p; *p能够访问1个字节
double *p;*p能够访问8个字节
例如:
#include<stdio.h>
int main()
{
printf("char=%d\n",sizeof(char*));
printf("short=%d\n", sizeof(short*));
printf("int=%d\n", sizeof(int*));
printf("double=%d\n", sizeof(double*));
return 0;
}
结果:
char=4
short=4
int=4
double=4
例如:
#include<stdio.h>
int main()
{
int a = 0x11223344;
int * pa = &a;
char* pc = &a;
printf("%p\n", pa);
printf("%p\n", pc);
return 0;
}
结果:
00EFFA00
00EFFA00
指针类型决定了:指针走一步走多远(指针的步长)
intp;p+1–>4
charp;p+1–>1
double*p;p+1–>8
指针的类型决定了指针向前或者向后走一步有多大距离(单位:bety字节)
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)char * 的指针解引用只能访问一个字节
int *的指针的解引用能访问四个字节
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。
3.指针变量作为函数参数
函数的参数可以是指针类型
作用:将一个变量的地址传送到另一个函数中
例如:对输入的两个整数按大小顺序输出。
#include<stdio.h>
int main()
{
void swap(int *p, int *p2);
int a, b;
int *p_1, *p_2;
printf("请输入两个整数:");
scanf("%d,%d", &a, &b);
p_1 = &a;
p_2 = &b;
if (a < b)
swap(p_1, p_2);
printf("max=%d,min=%d\n", a, b);
return 0;
}
void swap(int *p1, int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
结果:
请输入两个整数:5,9
max=9,min=5
- *p1就是a,是整形变量。但 *temp是指针变量temp所指向的变量
- p1是指针变量,应该等于地址,p1=&a
函数的调用只可以得到一个返回值,而使用指针变量作参数,可以得到多个变化了的值。
三、数组指针
数组指针指向的是数组,那数组指针中存放的应该是数组的地址,能够指向数组的指针
例如:
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
return 0;
}
arr表示的是数组的首地址
&arr 表示的是数组的地址
整形指针: int * pint; 能够指向整形数据的指针。
浮点型指针: float * pf; 能够指向浮点型数据的指针
1.数组元素的指针
数组元素的指针就是数组元素的地址
引用数组元素可以用下标法(如:a[3]),也可以是指针法——通过指向数组元素的指针找到所需元素
程序中的数组名不代表整个数组,只代表数组首元素的地址。
例如:
p=a;
作用:把a数组的首元素的地址赋给指针变量p
int *p=&a[0];等价于int *p;p=&a[0];等价于int *p=a;
int (*p)[10];
- p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。
- 注意:[ ]的优先级要高于号的,所以必须加上()来保证p先和结合。
2.引用数组元素时指针的运算
在指针已指向一个数组元素时
- p+1指向同一数组中的下一个元素,p-1指向同一数组中的上一个元素
- 若p的初值为&a[0],则p+i和a+i就是数组元素a[i]的地址,或者说,他们指向a数组序号为i的元素
- *(p+i)或 *(a+i)是p+i或a+i所指向的数组元素,即a[i]
- 若指针变量p1和p2都指向同一数组中的元素,若执行p2-p1,结果是p2-p1的值(两个地址之差)除以数组元素的长度
两个地址不能相加,p1+p2是无实际意义的
3.通过指针引用数组元素
引用一个数组元素,可以用两种方法:
- 下标法:a[i]形式
- 指针法:*(a+i)或 *(p+i)。其中a是数组名,p是指向数组元素的指针变量,其初值p=a。
例如:
int main()
{
int a[10];
int i;
printf("请输入10个整数:");
for (i = 0; i < 10; i++)
{
scanf("%d", &a[i]);
}
for (i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
结果:
请输入10个整数:0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
分析情况:
- p++;*p;
p++使p指向下一元素a[1],然后再执行*p,则得到下一个元素a[1]的值
- *p++;
等价于*(p++),先引用p的值,实现*p的运算,然后再使p自增1
- *(p++)与 *(++p)作用不同
*(p++)是先取 *p值,然后使p+1
(++p)是先使p+1,然后取 p
例如:
p=a;
输出(p++),得到a[0]的值
输出(++p),得到a[1]的值
- ++(*p)
表示p所指向的元素值加1
注意:是元素的值加1,而不是指针p的值加1
例如:
p=a;
++(*p)相当于++a[0],若a[0]=3;
执行++(*p)后,a[0]=4;
- 若p指向a数组中第i个元素a[i],则:
*(p - -)相当于a[i - -],先对p进行“ * ”运算(求p所指向的元素的值),在使p自减
*(++p)相当于a[++i],先使p自加,在进行“ * ”
*(- - p)相当于a[- - i],先使p自减,在进行“ * ”
4.用数组名作函数参数
以变量名和数组名作为函数参数的比较
实参类型 | 变量名 | 数组名 |
---|---|---|
要求形参的类型 | 变量名 | 数组名或指针变量 |
传递的信息 | 变量的值 | 实参数组首元素的地址 |
通过函数调用能否改变实参的值 | 不能改变实参变量的值 | 能改变实参数组的值 |
当用变量名作为函数参数时传递的是变量的值,当用数组名作为函数参数时,由于数组名代表的是数组首元素地址,因此传递的是地址,所以要求形参为指针变量。
实参数组名代表一个固定的地址,或者说是指针常量,但形参数组名并不是一个固定的地址,而是按指针变量处理
在函数调用进行虚实结合后,形参的值就是实参数组首元素的地址。在函数执行期间,可以再被赋值
实参用数组名,形参可以是数组名,也可用指针变量名