一、数组指针
1.数组指针本质上是一个指针变量,用于存储整个数组的起始地址;
2.对于数组指针而言,指针每偏移一个单位,内存就会偏移整个数组容量的大小;
3.数组指针一般用于二维数组,二维数组的数组名,本质上是一个数组指针常量;
4.数组指针的定义格式:数据类型 (*数组指针名)[常量];
例: int arr[5]={2,3,4,6,7};
int(*arr_ptr)[5]; //定义一个数组指针变量,变量名为arr_ptr
arr_ptr=&arr; //数组指针指向该数组
#include<myhead.h>
int main(int argc, const char *argv[])
{
int arr[5] = {4,8,3,2,6};
printf("sizeof(arr) = %ld\n", sizeof(arr));
printf("sizeof(&arr[0]) = %ld\n", sizeof(&arr[0]));
printf("sizeof(&arr) = %ld\n", sizeof(&arr));
//从数值上来说,这三个地址都一样
printf("arr = %p, &arr[0] = %p, &arr = %p\n", \
arr, &arr[0], &arr);
printf("arr+1 = %p, &arr[0]+1 = %p, &arr+1 = %p\n", \
arr+1, &arr[0]+1, &arr+1);
//定义一个数组指针指向 arr
int (*arr_ptr)[5] = &arr;
printf("数组元素分别是:");
for(int i=0; i<1; i++)
{
for(int j=0; j<5; j++)
{
printf("%d\t", arr_ptr[i][j]); // *((*arr_ptr+i)+j)
}
printf("\n");
}
for(int i=0; i<5; i++)
{
printf("%d\t", arr_ptr[0][i]);
}
printf("\n");
return 0;
}
#include<myhead.h>
int main(int argc, const char *argv[])
{
int arr[3][4] = {{1,2,3,4},{2,2,3,4},{4,4,4,4}};
//输出对应的地址
printf("&arr[0][0] = %p\n", &arr[0][0]); //普通变量的地址
printf("arr[0] = %p\n", arr[0]); //第一个数组数组名
printf("arr = %p\n", arr); //第一个数组的地址
printf("****************************************\n");
printf("&arr[0][0]+1 = %p\n", &arr[0][0]+1); //普通变量的地址
printf("arr[0]+1 = %p\n", arr[0]+1); //第一个数组数组名
printf("arr+1 = %p\n", arr+1); //第一个数组的地址
//从上述代码可以看出,arr是一个数组的起始地址,可以定义一个数组指针存放
int (*arr_ptr)[4] = arr;
//输出数组元素
printf("数组元素分别是:\n");
for(int i=0; i<3; i++)
{
for(int j =0; j<4; j++)
{
printf("%d\t", *(*(arr_ptr+i) + j)); //arr_ptr[i][j]
}
printf("\n");
}
return 0;
}
二、指针数组
1.本质上是一个数组,其中的元素为指针变量
2.格式定义:数据类型 * 数组名[数组长度];
3.案例
#include<myhead.h>
int main(int argc, const char *argv[])
{
//定义多个变量
int num = 520;
int key = 1314;
int value = 999;
//定义指针数组存储上面多个变量的地址
int *ptr_arr[3]; //此时定义了三个指针变量,分别是 ptr_arr[0]
//ptr_arr[1] ptr_arr[2]
//给指针变量赋值
ptr_arr[0] = #
ptr_arr[1] = &key;
ptr_arr[2] = &value;
//通过指针数组操作数据
for(int i=0; i<3; i++)
{
printf("%d\t", *ptr_arr[i]); //输出值
}
printf("\n");
printf("&num = %p, &key = %p, &value = %p\n", &num, &key, &value);
for(int i=0; i<3; i++)
{
printf("ptr_arr[%d] = %p\t",i , ptr_arr[i]);
}
printf("\n");
return 0;
}
三、指针函数
1.指针函数本质上是函数,函数的返回值类型是指针类型;
例如: char *strcpy();
2.定义格式:返回值类型 * 函数名(形参列表){函数体内容}
3.注意:返回值为指针类型的函数,返回结果是一个左值,函数调用的结果可以放在等号左侧
4.函数返回的地址,只能是生命周期比较长的存储空间的地址
1>全局变量
2>静态局部变量
3>主调函数以地址的形式传递到被调函数中的那块内存;
例如:char *strcpy();
4>使用malloc函数动态申请的堆区空间;
#include<myhead.h>
//定义指针函数
int *fun()
{
static int num = 520;
return #
}
/************************主程序********************/
int main(int argc, const char *argv[])
{
int *ptr = fun(); //定义指针接受返回结果
*ptr = 1314;
printf("*fun() = %d\n", *fun()); //1314
*fun() = 999; //对指针函数中的内容改变
printf("*ptr = %d\n", *ptr); //?
return 0;
}
四、函数指针
1.函数指针本质上是一个指针,指向函数的入口地址;
2.任何函数执行,系统都会在栈区为其分配一块用于执行的运行空间,有内存空间,就会有起始地址
#include<myhead.h>
//定义求和函数
int sum(int m, int n)
{
return m+n;
}
int main(int argc, const char *argv[])
{
int num = 520;
int key = 1314;
printf("result = %d\n", sum(num, key)); //函数调用
printf("sum = %p\n", sum); //函数名是函数入口地址
//定义函数指针,存储函数入口地址
int (*ptr_sum)(int, int); //此时定义了一个指针,该指针
//指向一个返回值为int类型,参数为两个int类型的函数入口地址
ptr_sum = sum; //此刻之后,所有使用sum的地方,都可以改成ptr_sum
printf("result = %d\n", ptr_sum(num, key)); //函数调用
return 0;
}
3.函数的名字就是函数的入口地址,如果想将函数作为另一个函数参数的话,可以用函数指针变量来接收,也就是所谓的回调函数;
4.用处:多线程创建时用到(IO进程线程)、数据库执行sql语句时用到(网络编程)、信号处理函数调用时会用到(IO进程线程);
5.函数指针的定义格式:数据类型(*指针名)(参数类型);
#include<myhead.h>
//定义求和函数
int jiafa(int m, int n)
{
return m+n;
}
//定义求差函数
int jianfa(int m, int n)
{
return m-n;
}
//定义求乘积函数
int changfa(int m, int n)
{
return m*n;
}
//定义计算函数
void jisuan(int x, int y, int (*ptr)(int, int))
{
printf("计算结果为:%d\n", ptr(x, y)); //完成函数回调
}
int main(int argc, const char *argv[])
{
int m = 520;
int n = 1314;
//调用计算函数
jisuan(m, n, jiafa);
jisuan(m, n, jianfa);
jisuan(m, n, changfa);
return 0;
}