知识点8【指针数组】
指针数组:本质数组 只是数组的每个元素位指针变量(保存地址编号)
指针数组 主要用于存放多个相同类型地址编号。
知识点9【指针变量的内存布局分析】
知识点10【字符数组和字符串指针变量的关系】
//字符数组:buf是数组 用数组本身的空间存储字符串
char buf[128]="hello world";
//字符串指针变量:buf是指针变量 保存了字符串"hello world"的首元素地址
//而"hello world"却在文字常量区
char *buf = "hello world";
char buf1[128]="hello world";
buf1[1]='E';//ok
char *buf2="hello world";
buf2[1]='E';//eror
知识点11【字符指针数组】
知识点12【指针的指针】
知识点13【数组指针】
1、一维数组的首元素地址和首地址。
printf("%d\n", *((int *)(&arr+1)-2)); == 40
2、数组指针
数组指针:本质是指针变量 保存的是数组的首地址。
3、数组指针 主要和 二维数组配合
一维数组指针int (*p)[4] 和二维数组名的int arr[3][4]操作等价
二维数组指针int (*p)[4][5]和三维数组名的int arr[3][4][5]操作等价
int arr[5];
int *p =arr;
//p是指针变量p++ 只占4B,但是arr不能++ arr的大小有元素的个数*每个元素的大小决定
int arr[3][4];
int (*p)[4];
//二维数组名 代表第0行的行地址 对行地址取* 代表当前行第0列的列地址 对列地址取* 代表元素值
arr[1]+1 第一行第1列的列地址
*arr+1 第0行第1列的列地址
**arr 第0行第0列的值
*(&arr[1]+1) == *(arr+2) == 第2行第0列的地址
*(arr+1)+1 第1行第1列的列地址
*arr[1]+1 第1行第0列的值+1
知识点14【指针作为函数的形参】
1、如果函数内部 要修改外部变量的值 必须传递外部变量的地址。
错误演示:
//单向传递:之传值 函数内部无法借助形参 修改外部变量的值
void set_data(int a)
{
a = 1000;
}
void test01()
{
int data = 10;
set_data(data);
printf("data=%d\n",data);//10
}
函数内部需要操作外部普通变量的值 需要将外部普通变量的地址 传递给函数
错误演示:
如果函数内部需要 给外部指针变量 修改指向 需要将外部指针变量的地址传递给函数
2、函数内部 想操作 外部一维数组 需要将一维数组名作为实参传递给函数。
所以:函数的形参 就是一维数组的元素指针变量。
//void my_print_int_array(int arr[5], int n)
void my_print_int_array(int *arr, int n)
{
int i=0;
for ( i = 0; i < n; i++)
{
//printf("%d ", *(arr+i));
printf("%d ", arr[i]);
}
printf("\n");
}
void my_input_int_array(int *arr, int n)
{
printf("请输入%d个int数值:",n);
int i=0;
for ( i = 0; i < n; i++)
{
scanf("%d", arr+i);
//scanf("%d", &arr[i]);
}
printf("\n");
}
int get_int_array_avg(int *arr,int n)
{
int sum=0,i=0;
for ( i = 0; i < n; i++)
{
sum+=arr[i];//如果是元素的值arr[i] 如果是元素地址arr+i
}
return sum/n;
}
void get_max_min_data(int *arr,int n,int *p_max,int *p_min)
{
int i=0;
//*p_max = arr[0];
int max = arr[0];
int min = arr[0];
for (i = 1; i < n; i++)
{
//*p_max = ((*p_max<arr[i])?arr[i]:*p_max);
max = ((max<arr[i])?arr[i]:max);
min = ((min>arr[i])?arr[i]:min);
}
//*p_max ==外部的max *p_min ==外部的min
*p_max = max;
*p_min = min;
return;
}
void test03()
{
int arr[5]={0};
int n=sizeof(arr)/sizeof(arr[0]);
my_input_int_array(arr, n);
my_print_int_array(arr, n);
//需求:求数组中的平均值
int avg = 0;
avg = get_int_array_avg(arr,n);
printf("平均值:%d\n", avg);
//需求:求数组中的最大值和最小值
int max=0,min=0;
get_max_min_data(arr,n,&max,&min);
printf("max=%d,min=%d\n",max,min);
return;
}
#include <string.h>
void input_char_array(char *buf, unsigned long len)
{
printf("请输入一个字符串:");
fgets(buf,len,stdin);
buf[strlen(buf)-1]='\0';
return;
}
void my_strcpy(char *dst, char *src)
{
while( (*dst=*src) && dst++ && src++ );
return;
}
void test04()
{
char buf[128]="";
//定义函数完成buf输入
input_char_array(buf, sizeof(buf));
char dst[128]="";
//定以函数完成strcpy
my_strcpy(dst, buf);
printf("dst=%s\n", dst);
}
一维数组作为函数的形参 会被优化成 元素指针变量。
int arr[5]------->int *arr
char arr[128]------>char *arr
3、如果函数内部 需要操作 外部二维数组元素 需要将二维数组名作为实参传递给函数。
所以:函数的形参 就是 数组指针。
实参----------->形参
int arr[3][4]------>int (*p)[4]
int arr[3][4][5]------>int (*p)[4][5]
char arr[3][128]---->char (*p)[128]
// void print_two_int_array(int arr[3][4],int row, int col)
void print_two_int_array(int (*arr)[4], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
// printf("%d ", *(*(arr+i)+j));
printf("%d ", arr[i][j]);
}
printf("\n");
}
return;
}
void test05()
{
int arr[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
int row = sizeof(arr) / sizeof(arr[0]);
int col = sizeof(arr[0]) / sizeof(arr[0][0]);
print_two_int_array(arr, row, col);
}
知识点15【函数的返回值为指针类型】
函数如果想 将函数内部空间 给外部使用 一般通过函数返回值 将内部空间起始地址 返回给外部。
所以函数的返回值类型必须是 指针类型。
1、注意:函数不要返回栈区的空间地址(函数结束 函数内部栈区空间将释放)
int *get_addr(void)
{
int data = 10;
return &data;
}
void test06()
{
int *p = NULL;
//函数结束 data的空间释放
p = get_addr();
//*p操作以释放的空间 多错误
printf("%d\n", *p);//段错误
}
2、函数内部要返回的空间 尽量全局区(static)、堆区
函数结束 全局区(static)、堆区空间 不会自动释放。
知识点16【函数指针】
函数指针:函数指针变量 保存函数的入口地址。
1、函数入口地址
在c语言中 函数名 代表函数的入口地址。
2、函数指针变量
本质:是变量 保存的是函数的入口地址。
int my_add(int a,int b)
{
return a+b;
}
int my_sub(int a,int b)
{
return a-b;
}
void test01()
{
int (*p)(int,int) = NULL;
printf("%lu\n",sizeof(p));//8B
p = my_add;
//函数调用的本质:入口地址+();
printf("%d\n", p(10,20));//30
printf("%d\n", my_add(10,20));//30
p = my_sub;
printf("%d\n", p(10,20));//-10
printf("%d\n", my_sub(10,20));//-10
}
3、函数指针变量的注意事项
不要对函数指针变量取* 无意义 编译器会优化调用。
不要对函数指针变量 ++ -- 无意义
函数指针变量 比较大小 无意义 (==除外)
4、函数指针的扩展
1、给函数指针类型取别名
int my_add(int a, int b)
{
return a + b;
}
int my_sub(int a, int b)
{
return a - b;
}
void test02()
{
//typedef 为已有的类型取别名
typedef int (*F_TYPE)(int, int);
F_TYPE p = my_add;
printf("%d\n", p(10,20));
}
2、函数指针 主要 作为函数的形参。
目的:让函数通用
int my_add(int a, int b)
{
return a + b;
}
int my_sub(int a, int b)
{
return a - b;
}
int my_mul(int a, int b)
{
return a * b;
}
int my_div(int a, int b)
{
return a / b;
}
// 需求:设计一个算法 完成加减乘除
int my_calc(int a, int b, int (*func)(int, int))
{
return func(a, b);
}
void test02()
{
printf("%d\n", my_calc(10, 20, my_add));
printf("%d\n", my_calc(10, 20, my_sub));
printf("%d\n", my_calc(10, 20, my_mul));
printf("%d\n", my_calc(10, 20, my_div));
}
案例:键盘输入add 10 20 sub 10 20 mul 10 20
int my_add(int a, int b)
{
return a + b;
}
int my_sub(int a, int b)
{
return a - b;
}
int my_mul(int a, int b)
{
return a * b;
}
int my_div(int a, int b)
{
return a / b;
}
#include <string.h>
void test02()
{
//函数指针数组 本质是数组 每个元素是函数的入口地址
int (*fun_arr[])(int,int) = {my_add,my_sub,my_mul,my_div};
int n = sizeof(fun_arr)/sizeof(fun_arr[0]);
//字符指针数组
char *cmd_buf[]={"add","sub","mul","div"};
printf("请输入操作命令(add 10 20):");
char cmd[32]="";
int data1=0,data2=0;
scanf("%s %d %d", cmd,&data1,&data2);
//核心代码
int i=0;
for ( i = 0; i < n; i++)
{
if(strcmp(cmd,cmd_buf[i]) == 0)
{
printf("%d\n", fun_arr[i](data1,data2));
}
}
return;
}