C 语言基础六: 指针
1. 访问内存地址
-
指针变量的数据类型和指向变量的类型需保持一致
-
每个变量都有一个内存地址,使用
&运算符访问
int a = 15;
int *p;
p = &a;
printf("a 指针地址: %p\n",p); //a 指针地址: 0x7ff7bfeff288
2. 如何使用指针
int var = 20;
int *ip;
ip = &var;
printf("var 变量的地址:%p\n",&var); //var 变量的地址:0x7ff7bfeff288
printf("var 变量存储指针地址:%p\n",ip); //var 变量存储指针地址:0x7ff7bfeff288
printf("var 变量的值:%d\n",*ip); //var 变量的值:20
3.空指针
- 变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋值为NULL
int *var = NULL;
printf("var 变量的地址:%p\n",var); //var 变量的地址:0x0
4. 打印指针占用的字节
- 指针变量占用内存的大小,跟数据类型无关,跟编译器有关系;
int c = 15;
int* c1 = &c;
char a = '0';
char* a1 = &a;
long long b = 400;
long long* b1 = &b;
printf("int : %zu \n",sizeof(c1)); // 8
printf("char : %zu \n",sizeof(a1)); // 8
printf("long long : %zu \n",sizeof(b1)); // 8
5. 指针的用法
- 作用一: 操作其他函数中的变量 - 交换变量
#include <stdio.h>
void swrp(int *num1,int *num2);
int main(void){
int a = 15;
int b = 20;
printf("变化前: a %d b %d \n",a,b); // 变化前: a 15 b 20
swrp(&a, &b);
printf("变化后: a %d b %d \n",a,b); //变化后: a 20 b 15
return 0;
}
void swrp(int *num1,int *num2){
int temp = *num1;
*num1 = *num2;
*num2 = temp;
}
- 作用二: 函数返回多个值-定义一个函数求数组的最大/最小值
#include <stdio.h>
void getMaxAndMin(int arr[],int len,int *max,int *min);
int main(void){
int arr[]= {1,2,3,4,5,6};
int len = sizeof(arr)/sizeof(int);
int max = arr[0];
int min = arr[1];
getMaxAndMin(arr, len, &max, &min);
printf("max:%d min:%d\n",max,min); //max:6 min:1
return 0;
}
void getMaxAndMin(int arr[],int len,int *max,int *min){
for (int i = 0;i < len; i++) {
if(arr[i] > *max){
*max = arr[i];
}
}
for (int i = 0;i < len; i++) {
if(arr[i] < *min){
*min = arr[i];
}
}
}
*作用三 : 函数的结果和计算状态分开 - 定义一个函数,获取余数
#include <stdio.h>
int getYs(int n1,int n2,int *res);
int main(void){
int a = 11;
int b = 6;
int res = 0;
int result = getYs(11, 6, &res);
if(!result){
printf("余数是%d \n",res); //余数是5
}
return 0;
}
// 返回值代表的正常不正常
int getYs(int n1,int n2,int *res){
if(n2 == 0){
return 1;
}
*res = n1 % n2;
return 0;
}
6. static小知识点
#include <stdio.h>
int* methods(void);
int main(void){
int *p = methods();
printf("坐下延时\n");
printf("坐下延时\n");
printf("坐下延时\n");
//不加static修饰 -147765566,methods结束后,函数里的变量随之消失
//加static修饰,正常打印
printf("%d\n",*p);
return 0;
}
int* methods(void){
static int a = 10; //此时的变量一直到程序结束
return &a;
}
7.指针运算(步长)
- 步长:指针移动一次,走了多少字节.和指针类型有关系.int移动4个,char移动1个
- 有意义的操作: 指针跟整数的
加/减操作(每次移动多少个步长); 指针和指针进行减操作(间隔步长)
int main(void){
int a = 10;
int * p = &a;
printf("%p \n",p); //0x7ff7bfeff288
printf("%p \n",p+1); //0x7ff7bfeff28c 移动4个字节
printf("%p \n",p+2); //0x7ff7bfeff290 移动8个字节
int arr[] = {0,1,2,3,4,5,6,7,8,9,10};
int * p1 = &arr[0];
//通过内存地址获取数据
printf("数组 %d\n",*p1); // 0
printf("数组 %d\n",*(p1 + 2)); // 2
//计算间隔步长
int * p2 = &arr[5];
//p2和p1的间隔步长
printf("间隔步长: %ld\n",p2 - p1); // 5
return 0;
}
8 野指针/悬空指针
- 野指针:指向的空间未分配
- 悬空指针: 指针指向的空间已分配,但是被释放了
#include <stdio.h>
int* methods(void);
int main(void){
int a = 10;
int * p = &a;
printf("L:%p \n",p); //L:0x7ff7bfeff288
printf("L:%d \n",*p); // L:10
//野指针
int * p1 = p + 10;
printf("K:%p \n",p1); //K:0x7ff7bfeff2b0
printf("K:%d \n",*p1); //K:0
//悬空指针
int *m = methods();
printf("拖点时间");
printf("拖点时间\n");
printf("F:%p \n",m); //F:0x7ff7bfeff25c
printf("F:%d \n",*m); //F:123312650
return 0;
}
int* methods(void){
int num = 10;
int *p = #
return p;
}
9. void *指针
// void *是一种特殊的指针类型,也被称为通用指针或者无类型指针,它可以指向任何类型的数据,但需要使用的时候需进行显示类型转换
// 特点:1.可以指向任何累心变量 2. 不包含所指向数据的类型信息 3.必须转换成具体类型才能访问数据 4.不能进行指针算术运算
int main(void){
// 定义两个变量
int a = 15;
short b = 16;
//定义两个指针
int* p1 = &a;
short* p2 = &b;
//不同类型的指针之间是不能相互赋值的
// void可以打破上面的观念
// void没有任何类型,好处可以接受任意类型记录的内存地址
void* p3 = p1;
void* p4 = p2;
//运算:无法获取指针指向的数据,也不能加减运算
// printf("%d \n",*p3); 报错
printf("%p \n",p3+1); //错误地址
return 0;
}
10.二级指针
- 指针数据类型:跟指向空间中,数据类型是保持一致的
- 二级指针可以操作一级指针记录的地址
//定义变量
int a= 15;
int b = 20;
//一级指针
int* p = &a;
//二级指针
int** PP = &p;
//作用一:利用二级指针修改一级指针里边记录的地址
*PP = &b;
printf("%p\n",&a); //0x7ff7bfeff288
printf("%p\n",&b); //0x7ff7bfeff284
printf("%p\n",p); //0x7ff7bfeff284
//作用二:利用二级指针获取到变量中记录的值
printf("%d\n",**PP); //20
11.利用指针遍历数组
int arr[] = {10,20,30,40,50};
int len = sizeof(arr)/sizeof(int);
//获取数组指针
int *p1 = arr;
int *p2 = &arr[0];
//两种方式获取到的地址一样
printf("%p\n",p1); //0x7ff7bfeff270
printf("%p\n",p2); //0x7ff7bfeff270
// 修改指针
printf("%d\n",*p1); // 10
printf("%d\n",*(p1+1)); //20
printf("%d\n",*(p1+2)); // 30
for (int i = 0; i < len; i++) {
printf("%d ",*p1);
p1++;
}
//10 20 30 40 50
12. 数组指针细节
- arr 参与计算的时候,会退化为第一个元素的指针
- 不会退化的情况: 1.
sizeof运算的时候,不会退化,还是整体 2.&arr获取地址的时候,不会退化
int arr[] = {10,20,30,40,50};
//不会退化,情况1
int len = sizeof(arr)/sizeof(int);
//情况2: &arr
printf("%p\n",arr); //0x7ff7bfeff270
printf("%p\n",&arr); //0x7ff7bfeff270
printf("%p\n",arr+1); //0x7ff7bfeff274 增加4步长
printf("%p\n",&arr+1); //0x7ff7bfeff284 // 增加20步长, 数据类型 * 数组长度 = 20