1、什么是指针:
指针就是地址,地址就是指针。(门牌号)
2、指针变量:存放变量地址的变量。
3、指针类型匹配:指针变量指向的是和它类型一致的变量的地址。
练习:
【1】封装一个函数实现两个数交换(函数传参用指针实现):01_pointer1.c
/*
* 封装一个函数实现两个数交换(函数传参用指针实现):
*/
#include <stdio.h>
void swap(int* data1,int* data2)
{
int tmp;
tmp = *data1;
*data1 = *data2;
*data2 = tmp;
}
int main()
{
int data1 = 10;
int data2 = 5;
printf("交换前: data1= %d data2= %d\n",data1,data2);
swap(&data1,&data2);
printf("交换后:data1= %d data2= %d\n",data1,data2);
return 0;
}
【2】输入三个数a,b,c,要求不管怎么输入,在输出时,a,b,c就是由大到小的顺序输出,用函数封装实现。(传参使用指针): 02_pointer2.c
/*
* 输入三个数a,b,c,要求不管怎么输入,在输出时,a,b,c就是由大到小的顺序输出,用函数封装实现。(传参使用指针)
*/
#include <stdio.h>
void number_comparisorison(int* p_data)
{
int i,j;
int tmp = 0;
for(i=0;i<3;i++)
{
for(j=0;j<3-i-1;j++)
{
if(*(p_data + j) < *(p_data + j+1))
{
tmp = *(p_data + j);
*(p_data + j) = *(p_data + j+1);
*(p_data + j+1) = tmp;
}
}
}
}
int main()
{
int arr[3];
int i;
for(i=0;i<3;i++)
{
scanf("%d",&arr[i]);
}
number_comparisorison(arr);
for(i=0;i<3;i++)
{
printf("%d\t",arr[i]);
}
printf("\n");
return 0;
}
4、定义一个指针变量指向数组
指针变量指向数组的首地址:a[0]。
示例:
int arr[3]; //创建一个数组
int* p_data; //创建一个指针
/******指针变量指向数组的方式*****/
【1】p_data = &arr[0]; //&arr[0]是数组的首元素地址
【2】p_data = arr; //arr是数组名,数组名是数组的首地址,是一个指针
5、通过指针偏移遍历数组:03_pointer3.c
/*
* 指针偏移遍历数组
*/
#include <stdio.h>
int main()
{
int i;
int arr[3] = {1,2,3};
int* p_data = arr;
/*指针变量数据的偏移*/
for(i=0;i<3;i++)
{
printf("%d\t",*(p_data+i));
}
printf("\n");
/*指针变量地址的偏移*/
for(i=0;i<3;i++)
{
printf("%p\n",p_data+i);
}
return 0;
}
指针偏移遍历方法二:(此方法由注意事项)
p_data = arr; //下面的指针每遍历一轮就需要重新指定数组的头
for(i=0;i<3;i++)
{
printf("%d",*(p_data++));
}
6、指针和数组名的关系(面试需要)
【1】指针当作数组名的下表法访问:04_pointer4.c
【2】数组名当指针用: 04_pointer4.c
/*
* 指针和数组名的关系
*/
#include <stdio.h>
int main()
{
int i;
int arr[3] = {1,2,3};
int* p_data = arr;
/*****指针当作数组名的下表法访问*****/
for(i=0;i<3;i++)
{
printf("%d\n",p_data[i]); //此时p_data[1] 和 arr[1]等价
}
/**********数组名当指针用***********/
for(i=0;i<3;i++)
{
printf("%d\n",*(arr+i)); //此时*(arr+1) 和 *(p_data+1)等价
}
return 0;
}
【3】printf("%d",*(arr++)); //*(arr++)是不允许的 这里的arr是指针常量
注:1】指针常量:指针常量指向的对象是可以修改的,但指针本身是不可以修改地址的。
2】指针变量:是存储地址的变量。它可以存储对象或函数的地址。
【4】sizeof(指针) 和 sizeof(数组)
1】printf("%d\n",sizeof(arr)); //占12个字节 数组中有3个元素 x int类型 4Byte = 12 Byte
2】printf("%d\n",sizeof(p_data)); //占8个字节 在64位系统中所有的指针变量都是8个字节
练习: 将数组中的n个元素按逆序输出(用函数实现功能)05_pointer5.c
/*
* 练习:将数组中的n个元素按逆序输出(用函数实现功能)
*/
#include <stdio.h>
void Reverse_output(int* p_data,int len)
{
int i = 0;
for(i=len-1;i>=0;i--)
{
printf("%d\t",*(p_data+i));
}
}
int main()
{
int arr[5];
int i;
int len = sizeof(arr)/sizeof(arr[0]); //计算数组的长度
printf("请输入数组中的元素\n");
for(i=0;i<len;i++)
{
scanf("%d",&arr[i]);
}
Reverse_output(arr,len);
return 0;
}
二维数组:二维数组的每一项都是一个数组。
7、二维数组的地址:06_pointer6.c
【1】一维数组中的每一项 " a[0] " 是数组的值
【2】二维数组中每一项 " a[0] " 是数组的地址
例:
int arr[2][3];
arr[1]:是一个数组名,数组中包含了3个元素。
arr:是数组名,是整个二维数组的首地址
arr[0][0] = arr[0]
/*
* 二维数组的地址问题:
*/
#include <stdio.h>
int main()
{
int arr[2][3];
printf("二维数组的地址:%p\n",arr);
printf("元素arr[0]:%p\n",arr[0]);
printf("元素arr[1]:%p\n",arr[1]);
printf("元素arr[0][0]:%p\n",&arr[0][0]);
printf("元素arr[0][1]:%p\n",&arr[0][1]);
return 0;
}
【3】二位数组的首地址 : int arr[2][3];
(1)arr : 二维数组的数组名
(2)arr[0] : 二维数组的首元素
(3)&arr[0][0] : 二维数组中首元素的首地址
arr[0] 等价于 &arr[0][0]
数组表示首地址:[1]数组名
[2]数组首元素的地址
【4】二维数组偏移问题: 把数组名当指针用
int arr[2][3];
(1)arr :数组名
(2)arr[0] : 数组首元素
*(arr+1)
(3)arr[0]+1 : arr[0]+1 :表示地址偏移是个指针
*(arr+0)+1
(4)*(arr[0]+1) : 表示arr[0][1] 的值
*(*(arr+0)+1)
8、数组指针 :数组指针就是指向数组的指针变量。它存储数组的地址,通过这个地址可以访问整个数组。
注:
:数组指针等同于二维数组名
:定义一个指针指向一个数组
【1】如何定义一个数组指针
类型 (*数组名)[大小];
int (*arr)[10]; //二维数组中一项中有几个元素,[ ] 中就填写几。
例:
int arr[2][3]; //定义一个二维数组
int (*p_arr)[3]; //定义一个数组指针
【2】如何使用数组指针:数组指针每次偏移指向的都是一个数组 07_pointer7.c
/*
* 如何定义一个数组指针并使用
* 数组指针等同与数组名
*/
#include <stdio.h>
int main()
{
int i;
int j;
int arr[2][3] = {
{1,2,3},
{4,5,6}
};
int (*p_arr)[3];
p_arr = arr;
/**********通过指针数组遍历二维数组********/
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("%d\t",*(*(p_arr+i)+j));
}
printf("\n"); //打印完一项换行
}
printf("done!\n");
}
练习:输出二维数组任意行、列的数 (函数实现) 08_pointer8.c
/*
* 数组指针:
* 题目:输出二维数组任意行、列的数(函数实现)
*/
#include <stdio.h>
/***********输出任意行列的值***********/
void output_lineAndlie(int (*p_arr)[4],int line,int lie)
{
printf("第%d行第%d的值是:%d\n",line+1,lie+1,*(*(p_arr+line)+lie));
}
int main()
{
int line; //行
int lie; //列
//
int arr[3][4] = {
{1,2,3,4}, //line 1
{5,6,7,8}, //line 2
{9,10,11,12} //line 3
};
printf("请输入行:");
scanf("%d",&line);
printf("请输入列:");
scanf("%d",&lie);
output_lineAndlie(arr,line,lie);
return 0;
}
9、函数指针
【1】函数指针的定义:如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段存储空间,这段存储空间的起始地址(又称入口地址)
称为这个函数的指针。
注:函数名就是地址(函数的起始地址)
注:函数指针是指向函数的变量
注:可以根据程序运行的不同情况,调用不同的函数
【2】定义函数指针变量
类型 (*变量名)(形参);
int (*func)(int data);
【2】通过函数指针调用函数
void func(int data) //创建一个函数
{
}
void (*p_func)(int data); //定义函数指针变量
p_func = func; //函数指针指向函数
(*p_func)(data); //调用函数
【2】附代码:通过函数指针调用函数 09_pointer9.c
/*
* 通过函数指针调用函数
*/
#include <stdio.h>
/******创建一个函数*****/
void func(int data)
{
printf("函数指针测试:");
printf("data = %d\n",data);
}
int main()
{
int data = 10;
void (*p_func)(int data); //创建一个函数指针
p_func = func; //函数指针指向函数
(*p_func)(data); //调用函数
return 0;
}
练习 : 有两个整数a和b,由用户输入1,2或3。如输入1,程序就给出a和b中大者,输入2,就给出a和b中小者,输入3,则求出a与b之和。10_pointer10.c
/*
* 练习 : 有两个整数a和b,由用户输入1,2或3。如输入1,程序就给出a和b中大者,输入2,就给出a和b中小者,输入3,则求出a与b之和。
*/
#include <stdio.h>
/*****最大值*****/
int outBigNum(int num1,int num2)
{
if(num1 > num2)
{
printf("最大值为num1,值为 %d\n",num1);
}
else
{
printf("最大值为num2,值为 %d\n",num2);
}
return 0;
}
/*****最小值*****/
int outSmallNum(int num1,int num2)
{
if(num1 < num2)
{
printf("最小值为num1,值为 %d\n",num1);
}
else
{
printf("最小值为num2,值为 %d\n",num2);
}
return 0;
}
/******求和******/
int sumNum(int num1,int num2)
{
int sum = 0;
sum = num1 + num2;
printf("两数字之和为:%d\n",sum);
}
int main()
{
int InData; //用户输出
int num1 = 10;
int num2 = 20;
int (*p_func)(int num1,int num2); //创建一个函数指针
printf("提示:\n 输入1求最大值\n 输入2求最小值\n 输入3求和\n");
scanf("%d",&InData);
switch(InData)
{
case 1:{
p_func = outBigNum; //函数指针指向函数(函数名是地址 )
(*p_func)(num1,num2); //调用函数(函数指针)
};break;
case 2:{
p_func = outSmallNum;
(*p_func)(num1,num2);
};break;
case 3:{
p_func = sumNum;
(*p_func)(num1,num2);
};break;
}
}
10、指针数组:一个数组,若其元素均为指针类型数据 ,称为指针数组。
【1】定义一个指针数组
类型 数组名[数组长度] ;
int* p[5]; //数组里面的每一项都是一个指针变量
特殊用法:int (*parr[5])(int data); //函数指针数组 //指针数组的每一项指向一个函数
函数指针初始化 :int (8parr[3])(int data) = {func1,func2,func3};
【1】附代码:11_pointer11.c
/*
* 指针数组示例
* 指针数组就是一个,每一项都是指针的数组
*/
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
int data1 = 10;
int data2 = 20;
int data3 = 30;
int data4 = 40;
int* arr[4] = {&data1,&data2,&data3,&data4}; //指针数组 :数组中每一项都是指针。
for(i=0;i<4;i++)
{
printf("%d\n",*arr[i]); //输出指针数组的每一项
}
return 0;
}
11、指针函数 :返回值的类型是指针类型
12、二级指针: int** p;
【1】多级指针存放的是指针变量的地址
【2】定义二级指针:int** p;
【3】二级指针示意:
int ⬅ int* ⬅ int**
【4】二级指针用来存储一级指针的地址
数据类型** 指针变量名 = & 一级指针变量名;
【5】二级指针图示;
代码验证:12_pointer12.c
#include <stdio.h>
/*
二级指针示意:
int ← int* ← int**
*/
int main()
{
int data = 100;
int *pointer;
int **pointer2;
pointer = &data;
pointer2 = &pointer;
puts("地址:");
printf("data的地址是:%p\n",&data);
printf("pointer的地址是:%p\n",&pointer);
printf("pointer2的地址是:%p\n",pointer2);
puts("值:");
printf("*pointer的值是:%d\n",*pointer);
printf("*pointer2的值是:%p\n",*pointer2);
printf("**pointer2的值是:%d\n",**pointer2);
puts("done!");
return 0;
}
【5】总结:
在二级指针中,int** p;
p 是一个地址(二级指针首地址)
*p 是一个地址
**p 是一个具体的值
注: 一些平时不会注意的操作:
int * p_data , p_str;
p_data 是一个指针变量
p_str 是一个整型变量
附:本文中所有代码
本文介绍了指针的基本概念,包括指针的定义、指针变量、类型匹配,以及如何通过指针进行数据交换、数组操作、函数传递和高级指针技巧,如指针数组和二级指针的使用。

1592

被折叠的 条评论
为什么被折叠?



