指针变量定义格式
查询数据
存储数据
// 利用指针去获取变量中的数据 /存储数据
int a = 10;
// 1.定义一个指针去指向变量a
int* p = &a;
// 2.利用指针去获取变量中的数据
printf("%d\n",*p);//10
// 3.利用指针去存储数据 /修改数据
*p = 200;
// 4.输出打印
printf("%d\n",*p);//200
printf("%d\n", a);//200
指针的使用细节
char c = 'a';
char* p1 = &c;
long long n = 100;
long long* p2 = &n;
printf("%zu\n", sizeof(p1));
printf("%zu\n", sizeof(p2));
小结
指针的作用
操作其他函数中的变量
#include <stdio.h>
void swap(int num1, int num2);
int main() {
// 1.定义两个变量
int a = 10;
int b = 20;
// 2.调用swap函数
printf("调用前:%d %d\n",a,b);//10 20
swap(a,b);//仅仅是把a和b中的值传递过去
printf("调用后:%d %d", a, b);//10 20
return 0;
}
void swap(int num1, int num2){//仅仅交换的是num1和num2里面记录的值
int temp = num1;
num1 = num2;
num2 = temp;
}
#include <stdio.h>
void swap(int* p1, int* p2);
int main() {
// 1.定义两个变量
int a = 10;
int b = 20;
// 2.调用swap函数
printf("调用前:%d %d\n",a,b);//10 20
swap(&a,&b);//把a和b中的地址传递过去
printf("调用后:%d %d", a, b);//20 10
return 0;
}
void swap(int* p1, int* p2){//此时交换的是p1指向的变量和p2指向的变量的值
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
细节
- 还有输出(输出10)的原因
printf("%d\n", *p);
前没有执行其他的代码,内存还没来得及回收
#include <stdio.h>
int* method();
int main() {
// 调用method函数,并使用该函数中的变量a
int*p = method();
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("%d\n", *p);// 不能打印的,因为method函数结束之后,该函数里面所有的变量也会随之消失
return 0;
}
int* method() {
int a = 10;
return &a;
}
#include <stdio.h>
int* method();
int main() {
// 调用method函数,并使用该函数中的变量a
int*p = method();
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("拖点时间\n");
printf("%d\n", *p);//10
}
int* method() {
static int a = 10;//此时变量一直保存到程序结束
return &a;
}
函数返回多个值
#include <stdio.h>
void getMaxAndMin(int arr[], int len, int* max, int* min);
int main() {
// 1.定义数组
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int len = sizeof(arr) / sizeof(int);
// 2.调用getMaxAndMin函数求最大值和最小值
int max = arr[0];
int min = arr[0];
getMaxAndMin(arr, len, &max, &min);
printf("数组的最大值为:%d\n", max);//10
printf("数组的最小值为:%d\n", min);//1
return 0;
}
void getMaxAndMin(int arr[], int len,int* max,int* min) {
//求数组的最大值
*max = arr[0];
for (int i = 1; i < len; i++) {
if (arr[i] > *max) {
*max = arr[i];
}
}
//求数组的最小值
*min = arr[0];
for (int i = 1; i < len; i++) {
if (arr[i] < *min) {
*min = arr[i];
}
}
}
函数的结果和计算状态分开
#include <stdio.h>
int getRemainder(int num1, int num2, int* res);
int main() {
// 1.定义两个变量
int a = 10;
int b = 3;
int res = 0;
int flag = getRemainder(a, b, &res);
if (!flag) {
printf("获取到的余数是:%d\n", res);//1
}
return 0;
}
//返回值:表示计算的状态 0为正常 1为不正常
//区分函数的结果和函数的运行状态
int getRemainder(int num1, int num2, int* res) {
if (num2 == 0) {
return 1;
}
*res = num1 % num2;
return 0;
}
指针高级
指针的计算
指针的加减
#include <stdio.h>
int main() {
/*
指针运尊:
步长:指针移动一次,走了多少个字节
char: 1
short: 2
int: 4
long: 4
long long: 8
加法:指针往后移动了N步 p + N
减法:指针往前移动了N步 p - N
*/
// 定义变量
int a = 10;
int* p = &a;
printf("%p\n", p); //00000077BFEFF884
printf("%p\n", p + 1); //00000077BFEFF888
printf("%p\n", p + 2); //00000077BFEFF88C
printf("%p\n", p); //000000D4594FF524
printf("%p\n", p - 1); //000000D4594FF520
printf("%p\n", p - 2); //000000D4594FF51C
return 0;
}
总结
指针的操作
#include <stdio.h>
int main() {
// 指针跟整数进行加、减操作(每次移动一个步长)
// 前提条件:保证内存空间是连续的
// 数组
int arr[] = {1,2,3,4,5,6,7,8,9,10 };
// 获取0索引的内存地址
int* p1 = &arr[0];
// 通过内存地址(指针p)获取数据
printf("%d\n", *p1);//1
printf("%d\n", *(p1 + 1));//2
// 指针跟指针进行减操作(间隔步长)
// 获取5索引的内存地址
int* p2 = &arr[5];
// p2 - p1 间隔了多少步长
printf("%d\n", p2 - p1); //5
//间隔了 5 * 4 = 20 个字节
printf("%p\n", p1); //0000000D4676F7C8
printf("%p\n", p2); //0000000D4676F7DC
return 0;
}
指向不明的指针
野指针
#include <stdio.h>
int main() {
// 野指针:指针指向的空间未分配
int a = 10;
int* p1 = &a;
printf("%p\n", p1); //000000893EFEF9D4
printf("%d\n", *p1); //10
//p2为野指针
int* p2 = p1 + 10;
printf("%p\n", p2); //000000893EFEF9FC
printf("%d\n", *p2); //137 有可能是其他程序的数据,不能随便改
return 0;
}
悬空指针
#include <stdio.h>
int* method();
int main() {
// 悬空指针:指针指向的空间已分配,但是被释放了
int* p2 = method();
printf("拖点时间\n");
printf("%p\n", p2); //00000040E60FF9C4
printf("%d\n", *p2); //-858993460 已释放,不是原来的数据
return 0;
}
int* method() {
int num = 10;
int* p = #
return p;
}
没有类型的指针
#include <stdio.h>
int main() {
// 1。 定义两个变量
int a = 10;
short b = 20;
// 2. 定义两个指针
int* p1 = &a;
short* p2 = &b;
// 3. 输出打印
printf("%d\n", *p1);//10
printf("%d\n", *p2);//20
// 不同类型的指针之间,是不能互相赋值的
//char* p3 = p1;报错
// void类型的指针打破上面的观念
// void没有任何类型,好处可以接受任意类型指针记录的内存地址
void* p3 = p1;
void* p4 = p2;
// 缺点:void类型的指针,无法获取变量里面的数据,也不能进行加、减的计算
//printf("%d\n",*p3);报错
//printf("%p\n",p3 + 1);报错
return 0;
}
#include <stdio.h>
void swap(void* p1, void* p2, int len);
int main() {
//调用函数交换数据
int c = 100;
int d = 200;
swap(&c, &d, 4);
printf("c = %d,d = %d", c, d);
return 0;
}
// 函数:用来交换两个变量记录的数据
// 修改一下函数,更具有通用性
void swap(void* p1, void* p2, int len) {
// 把void类型的指针,转成char类型的指针
char* pc1 = p1;
char* pc2 = p2;
char temp = 0;
// 以字节为单位,一个字节一个字节的进行交换
for (int i = 0; i < len; i++) {
temp = *pc1;
*pc1 = *pc2;
*pc2 = temp;
pc1++;
pc2++;
}
}
二级指针和多级指针
#include <stdio.h>
int main() {
/*
二级指针
格式:数据类型** 指针名
*/
//定义变量
int a = 10;
int b = 20;
//定义一级指针
int* p = &a;
//定义二级指针
int** pp = &p;
//作用一:利用二级指针修改一级指针里面记录的内存地址
*pp = &b;
//输出打印
printf("%p\n",&a); //0000001749B5F664
printf("%p\n",&b); //0000001749B5F684
printf("%p\n",p); //0000001749B5F684
// 作用二:利用二级指针获取到变量中记录的数据
// *pp 获取到一级指针所记录的地址
// **pp 通过一级指针所记录的地址,再去获取到变量里的数据
printf("%d\n", **pp);//20
return 0;
}
数组指针
#include <stdio.h>
int main() {
/*
练习:利用指针遍历数组
*/
// 1.定义数组
int arr[] = {10,20,30,40,50};
int len = sizeof(arr) / sizeof(int);
// 2.获取数组的指针
// 实际上获取的:数组的首地址
int* p1 = arr;
int* p2 = &arr[0];
printf("%p\n", p1); //0000000FAE59F9E8
printf("%p\n", p2); //0000000FAE59F9E8
//3.利用循环和指针追历数组获取里面的每一个元素
for (int i = 0; i < len; i++) {
printf("%d\n", *p1++);
}
return 0;
}
细节
#include <stdio.h>
int main() {
// 1.定义数组
int arr[] = {1,2,3,4,5,6,7,8,9,10};
// 2.sizeof 运自的时候,不会退化,arr还是整体
printf("%zu\n",sizeof(arr));//40
// 3.&arr 获取地址的时候,不会退化,记录的内存地址第一个元素的首地址,也是数组的首地址,步长:数据类型*数组的长度 40
// arr 参与计算的时候,会退化为第一个元素的指针,记录的内存地址第一个元素的首地址,也是数组的首地址,步长:数据类型 int 4
printf("%p\n",arr); //0000000B9256F948
printf("%p\n",&arr); //0000000B9256F948
printf("%p\n",arr + 1); //步长:4
printf("%p\n",&arr + 1);//步长:40
return 0;
}
总结
二维数组
定义格式
索引操作
#include <stdio.h>
int main() {
/*
二维数组
定义格式和遍历方式
定义格式方式一:
m:表示二维数组的长度
n:表示每一个-维数组的长度
数据类型 arr[m][n]=
{
{1,2,3,4,5....},
{1,2,3,4,5....},
{1,2,3,4,5....}
};
遍历:利用索引进行遍历 / 利用指针进行遍历
*/
// 1.定义一个二维数组
int arr[3][5] =
{
{1, 2, 3, 4, 5},
{11, 22, 33, 44, 55},
{111,222,333,444,555}
};
// 2.利用索引的方式进行遍历
// arr[0]:表示二维数组当中的第一个一维数组,{1,2,3,4,5}
// arr[1]:表示二维数组当中的第二个一维数组,{11,22,33,44,55}
// arr[2]:表示二维数组当中的第三个一维数组,{111,222,333,444,555}
for (int i = 0; i < 3; i++) {
// i:依次表示二维数组中的索引
for (int j = 0; j < 5; j++) {
// j:依次表示一维数组中的索引
// 内循环:遍历每一个一维数组
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
#include <stdio.h>
int main() {
/*
二维数组的定义格式二 + 索引遍历
核心:事先先把所有的一维数组定义完毕,再放入到二维数组当中
*/
// 1.定义三个一维数组
int arr1[3] = {1,2,3};
int arr2[5] = {1, 2, 3, 4, 5};
int arr3[9] = {1,2,3,4,5,6,7,8,9};
//预先计算每一个数组真实的长度
int len1 = sizeof(arr1) / sizeof(int);
int len2 = sizeof(arr2) / sizeof(int);
int len3 = sizeof(arr3) / sizeof(int);
// 再定义一个数组,装所有数组的长度
int lenArr[3] = {len1, len2, len3};
// 2.把三个一维数组放入到二维数组当中、
// 数组的数据类型,跟内部存储的元素类型保持一致
// arr1:使用数组名进行计算的时候,退化为指向第一个元素的指针,此时不再表示数组的那个整体了
// 指针---内存地址 在64位win中 8个字节
int* arr[3] = {arr1,arr2,arr3};//arr存储的是一维数组的地址
// 3.利用索引遍历arr
for (int i = 0; i < 3; i++) {
for (int j = 0; j < lenArr[i]; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
指针操作
#include <stdio.h>
int main() {
/*
二维数组
利用指针遍历二维数组
*/
// 1.定义一个二维数组
int arr[3][5] =
{
{1,2,3,4,5},
{11, 22, 33, 44, 55},
{111,222,333,444,555}
};
// 2.利用指针遍历二维数组
// 获取二维数组的指针
// 数组指针的数据类型:要跟数组内部元素的类型保持一致
// 二维数组里面存储的是一维数组
int(*p)[5]= arr;
// 相差20个字节
printf("%p\n",arr); //000000943A2FF808
printf("%p\n", arr + 1); //000000943A2FF81C
for (int i = 0; i < 3; i++) {
// 遍历一维数组
for (int j = 0; j < 5; j++) {
printf("%d ", *(*p + j));
}
// 换行
printf("\n");
//移动二维数组的指针,继续遍历下一个一维数组
p++;
}
return 0;
}
#include <stdio.h>
int main() {
/*
二维数组
利用指针遍历二维数组
*/
// 1.定义三个一维数组
int arr1[5] = {1,2,3,4,5};
int arr2[5] = {11,22,33,44,55};
int arr3[5] = {111,2222,333,444,555};
// 2. 把三个一维数组的内存地址,再放入到二维数组中
int* arr[3] = {arr1,arr2,arr3};
// 3.获取指针
int** p = arr;
// 4. 遍历数组
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
printf("%d ", *(*p + j));
}
// 换行
printf("\n");
//移动二维数组的指针,继续遍历下一个一维数组
p++;
}
return 0;
}
数组指针和指针数组
函数指针
#include <stdio.h>
void method1();
int method2(int num1, int num2);
int main() {
/*
函数指针
*/
// 1. 定义指针指向两个函数
void (*p1)() = method1;
int (*p2)(int num1, int num2) = method2;
// 2.利用函数指针去调用函数
p1();
int num = p2(10, 20);
printf("%d\n", num);
return 0;
}
void method1() {
printf("method1\n");
}
int method2(int num1, int num2) {
printf("method2\n");
return num1 + num2;
}
练习
#include <stdio.h>
int add(int num1, int num2);
int subtract(int num1, int num2);
int mutiply(int numl, int num2);
int divide(int numl, int num2);
int main() {
// 1.定义一个数组去装四个函数的指针
// 函数指针数组
// 细节:只有形参完全相同而且返回值也要一样的函数,才能放到同公个函数指针数组当中
int(*arr[4])(int,int) = {add,subtract,mutiply,divide};
// 2.用户键盘录入三个数据
printf("请录入两个数字参与计算\n");
int num1;
int num2;
scanf("%d%d", &num1, &num2);
int choose;
printf("请录入一个数字表示要进行的计算\n");
scanf("%d", &choose);
// 3.根据用户的选择,来调用不同的函数
int res = (arr[choose -1])(num1,num2);
// 4.输出打印
printf("%d\n", res);
return 0;
}
int add(int num1, int num2) {
return num1 + num2;
}
int subtract(int num1, int num2) {
return num1 - num2;
}
int mutiply(int num1, int num2) {
return num1 * num2;
}
int divide(int num1, int num2) {
return num1 / num2;
}