回顾
上一章我们对宏定义有了基本的了解,刚开始的确会觉得这是一个很抽象的概念,但在我们逐渐练习中会有更深入的理解,学习它的确会觉得这是一个很难的东西,根本就不知道这是什么玩意,我就更需要花费时间去学习
学习内容
九、指针
1. 地址与指针变量的概念,地址运算符与间址运算符。
2.一维、二维数组和字符串的地址以及指向变量、数组、字符串、函数、结构体的指针变量的 定义。通过指针引用以上各类型数据。
3.用指针作函数参数。
4.返回地址值的函数。
5.指针数组,指向指针的指针。
学习章节
(一)地址与指针变量的概念,地址运算符与间址运算符
学习指针我们要先认识指针
什么是指针
指针就是内存地址
我们打一个比方
咱们可以把内存想象成一个大旅馆,每个房间都有一个编号(内存地址)。而指针呢,就像是一个能记住房间编号的小纸条。
通过这个小纸条(指针),我们就能找到对应的房间(内存地址),然后对房间里的东西(数据)进行操作。
指针的作用
后面有代码练习分析作用
1.操作其他函数中的变量
2.函数返回多个值
3.函数的结果和计算状态分开
4.方便操作数组和函数
(二)一维、二维数组和字符串的地址以及指向变量、数组、字符串、函数、结构体的指针变量的 定义。通过指针引用以上各类型数据
指针变量的定义
存储内存地址的变量
格式
数据类型 * 变量名
图片
利用指针获取变量的数据
代码如下
//利用指针获取变量的数据
#include<stdio.h>
int main(){
int a=10;
//1.定义一个指针指向变量啊
int *p=&a;
//2.指针获取变量的数据
printf("%d\n",*p);
//指针修改数据
*p=100;
printf("%d\n",a);
printf("%d\n",*p);
return 0;
}
数组指针
就是指向数组的指针
利用指针遍历数组
//利用指针遍历数组 (数组指针)
#include<stdio.h>
int main(){
int arr[]={12,3,4,67,89,78,67,56,45};
int len=sizeof(arr)/sizeof(int);
//用指针去获取数组
int *p1=arr;
int *p2=&arr[0];
//这里都可以获取数组的首地址
printf("%p\n",p1);
printf("%p\n",p2);
//利用指针遍历数组的每一个元素
for(int i=0;i<len;i++)
{
printf("%d\n",*p1++);
}
return 0;
}
注意细节
arr参与计算的时候就是数组的第一个元素
用索引的方式遍历二维数组
代码如下
//用索引的方式遍历二维数组
#include<stdio.h>
int main(){
int arr[3][5]={
{9,8,7,6,5},
{99,83,74,56,54},
{91,82,74,66,58},
};
//其实这个3就代表了3个一维数组 5代表一个一维数组里面有几个数
for(int i=0;i<3;i++){
for(int j=0;j<5;j++){
printf("%d\t", arr[i][j]);
}
printf("\n");
}
return 0;
}
*/
//如果二维数组的长度不一样
#include<stdio.h>
int main(){
int arr1[3]={1,2,3};
int arr2[5]={1,2,3,4,5};
int arr3[6]={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};
//用指针表示
int*arr[3]={arr1,arr2,arr3};
for(int i=0;i<3;i++){
for(int j=0;j<lenarr[i];j++){
printf("%d ",arr[i][j]);
}
printf("\n");
}
}
注意代码不能直接运行,有注释符号
用指针遍历二维数组
//用指针遍历一个二维数组
#include<stdio.h>
int main(){
int arr[3][5]={
{1,2,3,4,5},
{22,33,44,55,66},
{33,44,55,66,77},
};
//获取二维数组的指针
int (*p)[5]=arr;
for(int i=0;i<3;i++){
for(int j=0;j<5;j++){
printf("%d ",*(*p+j));
}
printf("\n");
p++;
}
return 0;
}
//第二个方法是获取指针的方式不一样 int **p=arr 其他都一样
指针获取字符串
两种格式
方法一 char str[4]="abc"
注意 有结束标记 内容可以修改
方法二 char *str="abc"
注意 有结束标记\n 只能读,内容不能修改 因为存的是地址会复用
太抽象我们可以代码理解
//用指针获取字符串
#include<stdio.h>
int main()
{
//方法一
char str1[4]="abc";//{'a','b','c','\0'} 所以要定义为4
printf("%s\n",str1);
//可以修改
str1[0]='w';
printf("%s\n",str1);
//方法二 指针字符串
char* str2="abcd";//{'a','b','c','d','\0'}
//注意不能修改 str2[0]='q'
printf("%s\n",str2);
//字符串就是地址可以复用不会改变
char* str3="abcd";
printf("%p\n",str2);
printf("%p\n",str3);
return 0;
}
我们尝试用键盘输出一个字符串并进行遍历
//用键盘输出字符串并进行遍历
#include<stdio.h>
int main(){
char str[100];
printf("请输入一个字符串:\n");
scanf("%s",str);
printf("接受到的字符串为: %s\n",str);
//用指针遍历
char* p=str;
while(1){
//用指针获取字符串的每一个字符,直到遇到\n
char c=*p;
if(c==0){
break;
}
printf("%c\n",c);
p++;
}
return 0;
}
(三)用指针作函数参数 函数指针
函数指针
格式 返回值类型 (*指针名) (形参列表)
作用:利用函数指针,可以动态的调用指针
代码 里面有函数的形参
//函数指针
#include<stdio.h>
void method1(){
printf("method1\n");
}
int method2(int num1,int num2){ //这里是形参
printf("method2\n");
return num1+num2;
}
int main(){
//定义两个指针指向两个函数
void (*p1)()=method1;
int (*p2)(int,int)=method2;
//利用函数指针去调用函数
p1();
int num=p2(11,22);
printf("%d\n",num);
return 0;
}
这里我们在来稍微比较难的东西,真的有点抽象,就是用指针去存相同类型的函数,这个也是函数指针,然后去选择函数进行运算
题目:键盘输入两个数,然后选择调用的函数用函数指针
1.加 2.减 3.乘 4. 除
//题目:键盘输入两个数,然后选择调用的函数用函数指针
//1.加2.减3.乘 4. 除
//函数指针
#include<stdio.h>
int add(int num1,int num2){
return num1+num2;
}
int subtract(int num1,int num2){
return num1-num2;
}
int multiply(int num1,int num2){
return num1*num2;
}
int divide(int num1,int num2){
return num1/num2;
}
int main(){
int (*arr[4])(int,int)={add,subtract,multiply,divide};
printf("请输入两个数字:\n");
int num1;
int num2;
scanf("%d%d",&num1,&num2);
int choose;
printf("请输入一个数字你要进行的计算(1.加2.减3.乘 4. 除): \n");
scanf("%d",&choose);
int res=(arr[choose-1])(num1,num2);
printf("%d",res);
return 0;
}
(四)返回地址值的函数,指针的运算
指针的运算
我们可以从打印地址开始学起
打印指针就是在打印地址
指针的运算规则
指针移动了一次,走了多少个字节
char :1 short:2 int :4 long :4 longlong :8
如下代码
#include<stdio.h>
int main(){
int a=10;
int*p=&a;
printf("%p\n",p);
printf("%p\n",p+1);
printf("%p\n",p+2);
return 0;
}
指针加一或者指针减一 就是内存地址往前移动或者往后移动一个步长
步长和数据类型有关,上面有 这里的p是打印地址哦,别看错了
学习用指针地址获取值
#include<stdio.h>
int main()
{
//指针和整数进行加减操作(每次移动一个步长)
//指针和指针进行减操作(间隔步长)
int arr[]={1,2,3,4,5,6,7,8,9};
int *p1=&arr[0];
//通过指针获取数据
printf("%d\n",*p1);
printf("%d\n",*p1+1);//2
//获取索引6的地址
int *p2=&arr[6];
//计算p1和p2间隔的步长
printf("%d\n",p2-p1);
printf("%p",p1);
printf("%p",p2);
return 0;
}
注意细节
1.指针和整数不要进行乘除操作
2.指针和指针之间不进行加乘除操作
否则就没有意义
(五)指针数组,指向指针的指针
什么是指针数组
存放指针的数组
例如 int *arr[2]={ arr1,arr2};
比较一下数组指针和指针数组
指向指针的指针就是二级指针
如下代码
//二级指针的作用
#include<stdio.h>
int main(){
int a=10;
int b=20;
//定义的是一级指针
int*p=&a;
//定义二级指针
//这个p是指向的,记得不要重名哦
int**pp=&p;
//作用一 :二级指针可以更改一级指针的地址
//这里有点绕,因为二级指针的引用就是一级指针
*pp=&b;
// 作用二:利用二级指针获取变量的数据
printf("%d\n",**pp);
printf("%p\n",&a);
printf("%p\n",&b);
printf("%p\n",p);
return 0;
}
代码练习
练习一 定义两个变量,用指针交换地址,使用交换函数 (指针的作用一)
void swap(int *p1,int *p2){
int temp=*p1;
*p1=*p2;
*p2=temp;
}
#include<stdio.h>
int main(){
int a=10;
int b=50;
printf("调用swap之前的:%d,%d\n",a,b);
swap(&a,&b);
printf("调用swap之后的:%d,%d\n",a,b);
return 0;
}
练习二 利用函数返回多个值,求最值 (指针的作用二)
#include<stdio.h>
//利用函数指针求最大值
void getmaxmin(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];
}
}
}
int main(){
int arr[]={1,2,3,3,4,5,6,7,8,9};
int len=sizeof(arr)/sizeof(int);
int max=arr[0];
int min=arr[0];
getmaxmin(arr,len,&max,&min);
printf("最大值为:%d,最小值为%d\n",max,min);
return 0;
}
练习三 (指针的作用三)
函数的结果和状态分开
定义一个函数,将两个数相除,并获取余数
//函数的结果和状态分开
//定义一个函数,将两个数相除,并获取余数
#include<stdio.h>
int getyushu(int num1,int num2,int*res){
if(num2==0){
return 1;
}
*res=num1%num2;
return 0;
}
int main(){
int a=10;
int b=3;
int res=0;
int flag=getyushu(a,b,&res);
if(!flag){
printf("余数为%d\n",res);
return 0;
}
}
练习四 键盘输入字符串,指针遍历
//用键盘输出字符串并进行遍历
#include<stdio.h>
int main(){
char str[100];
printf("请输入一个字符串:\n");
scanf("%s",str);
printf("接受到的字符串为: %s\n",str);
//用指针遍历
char* p=str;
while(1){
//用指针获取字符串的每一个字符,直到遇到\n
char c=*p;
if(c==0){
break;
}
printf("%c\n",c);
p++;
}
return 0;
}
练习五 遍历二维的字符串数组用指针
//字符串数组
//用指针去遍历字符串就行
//这个是二维数组
#include<stdio.h>
int main(){
char strArr[3][20]={
"zhangzhang",
"lili",
"xiaoxiao"
};
//方法一
//遍历二维数组
for(int i=0;i<3;i++){
//表示二维数组的索引
char *str=strArr[i];
printf("%s\n",str);
}
printf("===============================\n");
//方法二 5个字符串的指针,放到一个数组
char *strArr2[3]={
"zhangzhang",
"lili",
"xiaoxiao"
};
for(int i=0;i<3;i++){
char*str=strArr2[i];
printf("%s\n",str);
}
return 0;
}