再探指针
一、指针的操作
(三目运算符 a>b?a:b)
#include <stdio.h>
int main(){
int a=100;
int b=200;
a>b?a:b;//判断:若a>b则输出a,否则输出b
return 0;
}
1.指向常量的指针与指针常量
const char*p;//定义一个指向常量的指针
char *const p;//定义一个指针常量,一旦初始化后其内容不可改变
#include <stdio.h>
int main(){
/*int x=200;
int* p=&x;//p指针指向x变量绑定的内存段
*p=100;//修改p指向内存的内存段中的数据
printf("%d",x);//结果:输出100
*/
int x=1086;
//指向常量的指针 值变成常量
const int* q=&x;
// *q=52;//会报错
q=(int*)10086;
//指针常量:不可以改变的指针数据 地址变成常量
int* const p=&x;
*p=10;
//p=10086;//会报错
const int* const p1=&x;//值和地址都不可变
// *p1=10;报错
// p1=10086;报错
return 0;
}
2.指针与数组的关系
一个变量有地址,一个数组包含若干个元素,每个元素在内存中都有地址。数组在内存空间的地址是连续的。
指针:变量的首地址
数组的变量名就是数组的首地址
*解引用
#include <stdio.h>
int main(){
int arr[5]={11,12,45,2,3};
// printf("%d\n",sizeof(arr));//占20个字节
int* p=&arr[0];//p指向arr[0]这个空间的首地址
//不能使用int* p=&arr;
int* p1=arr;//数组的变量名就是数组的首地址
printf("%d\n",*p);//此处结果输出为11
printf("%d\n",*p1);//*p1解引用,此处结果输出为11
printf("%d\n",arr[0+1]);//输出数组的第二个数据
printf("----------------\n");
printf("%#X\n",p);//输出地址相同
printf("%#X\n",p1);
printf("%#X\n",arr);
return 0;
}
3.指针运算
指针运算不是简单的整数加减法,而是指针指向的数据类型在内存中占用字节数做为倍数的运算。
char *p;
p++; //移动了sizeof(char)这么多字节
int* p1;
p1++; //移动了sizeof(int)这么多字节
赋值:int *p = &a;
求值:int I = *p;
取指针地址 int **pp = &p;
将一个整数加(减)给指针:p + 3; p – 3;
增加(减少)指针值 p++,p--
求差值 ,p1 – p2,通常用于同一个数组内求两个元素之间的距离
比较 p1 == p2,通常用来比较两个指针是否指向同一个位置。
#include <stdio.h>
int main(){
int x=10086;//int 类型占据4个字节
// 0000 0000 0000 0000 0010 0111 0110 0110
// p
char* p=(char*)&x;//p指向x的最低位
*(p+3)=128;//使得输出x为负数
//二进制位负数,最高位是1,
// 1000 0000 即2^7=128
printf("%d\n",x);
return 0;
}
4.通过指针使用数组元素
p + 1代表&a[1],也可以直接使用p[1]表示a[5]
p + 5 代表&a[5]
p++
#include <stdio.h>
int main(){
int arr[5]={11,12,45,2,3};
int* p=arr;
//for(int i=0;i<5;i++){printf("%d\t",p[i]);}
// 结果:11 12 45 2 3
double* q=(double*)arr;
printf("%d\n",*(q+1));
//q是8个字节,+1是步长移动8个字节,int型数据是4个字节,即数据移动到45
return 0;
}
5.指针数组
指针数组:指向指针的数组
int *p[5];
#include <stdio.h>
int main(){
int arr[5]={11,12,45,2,3};
int arr1[7]={1,2,3,4,5,6,7};
//int* p[5]=arr;//报错
int* p[5];//数组名为p,[5]是5个int类型的指针
p[0]=arr;
int i;
for (i = 0; i < 5; i++) {
printf("%d\t", p[0][i]);
}
printf("\n");
return 0;
}
//结果输出:11 12 45 2 3
#include <stdio.h>
int main(){
int arr[5]={11,12,45,2,3};
int arr1[7]={1,2,3,4,5,6,7};
int* p[5];
p[0]=arr;
p[1]=arr1;
int i;
for (i = 0; i < 7; i++) {
printf("%d\t", p[1][i]);
}
printf("\n");
return 0;
}
//结果输出:1 2 3 4 5 6 7
6.指向指针的指针(二级指针)
指针就是一个变量,既然是变量就也存在内存地址,所以可以定义一个指向指针的指针。
int i = 10;
int *p1 = &i;
int **p2 = &p1;
printf("%d\n", **p2);
以此类推可以定义3级甚至多级指针。C语言允许定义多级指针,但是指针级数过多会增加代码的复杂性,考试的时候可能会考多级指针,但实际编程的时候最多用到3级,但3级指针也不常用,一级和二级指针是大量使用。
7.指向二位数组的指针
数组指针是指针 ,指针数组是数组
| int buf3 | 二维数组名称,buf代表数组首地址 |
|---|---|
| int (*a)[5] 数组指针 行指针 | 定义一个指向int [5]类型的指针变量a |
| a[0], *(a + 0), *a | 0行,0列元素地址 |
| a + 1 | 第1行首地址 |
| a[1], *(a + 1) | 第1行,0列元素地址 |
| a[1] + 2, *(a + 1) + 2, &a1 | 第1行,2列元素地址 |
| *(a[1] + 2), ((a + 1) + 2), a1 | 第1行,2列元素的值 |
#include <stdio.h>
int main(){
int buf[3][5]={{1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15}};
//数组指针又叫行指针,用指针指向二维数组的行号,即(*a)
int(*a)[5]=buf;//*a=buf[0] *a+1=buf[1]
// *a\a[0]\*(a+0) 表示第一行数据
// *(a+1)\a[1] 表示第二行数据
return 0;
}
#include <stdio.h>
int main(){
int x=10;
int p=(int)&x;//p指向x的地址
//修改p的数据
*((int*)p)=50;//等同于 *(int*)p,括号前加*为解引用
//(int*)p:p是int 类型的指针,
printf("%d\n",x);//输出结果为50
return 0;
}
8.指针变量做为函数的参数
函数的参数可以是指针类型。,它的作用是将一个变量的地址传送给另一个函数。
通过函数的指针参数可以间接的实现形参修改实参的值
#include <stdio.h>
void Ch(int x){x=10086;}
int main(){
int x=100;
Ch(x);
printf("%d\n",x);
return 0;
}//结果输出:100
#include <stdio.h>
void Ch(int* x){
*x=10086;}//x是一个指针
int main(){
int x=100;
Ch(&x);
printf("%d\n",x);
return 0;
}//结果输出:10086
9.一维数组名作为函数参数
当数组名作为函数参数时,C语言将数组名解释为指针
int func(int arr[10]);//arr是指针
#include <stdio.h>
void Ch(int x[5]){
int i;
for(i=0;i<5;i++){
*(x+i)=i;}
}
int main(){
int arr[5]={11,12,45,2,3};
Ch(arr);
for( int i=0;i<5;i++){
printf("%d\n",arr[i]);
}
return 0;
}
/*结果输出:
0
1
2
3
4
*/

浙公网安备 33010602011771号