数组:
int arr[10]
arr:代表数组首元素的地址即&arr[0]
&arr:代表整个数组的地址。
int* p=arr;
int (*p1)=&arr;
数组名在两种情况下代表整个数组:
sizeof(arr) &arr+1
字符串指针
字符串在内存中仅有一份,在rodate段,不可修改
如果需要修改,拷贝一份到数组修改
int main()
{
*str1="hello word";//"hello word"这个字符串在内存中仅有一份,在rodate段
*str2="hello word";//不可修改,如果想要修改,放在数组中。
*str3[]="hello word";
*str4[]="hello word";
//str1=str2 str3!=str4
return 0;
}
指针数组与数组指针
指针数组:包含指针元素的数组 eg:void *p[10]
指针数组是一个只包含指针元素的数组,它的元素可以指向相同类型的不同对象
数组指针 : 指向一个数组的指针 eg: void (*p)[10]
数组指针就是一个指针变量,它指向一个数组
数组指针的使用:存放数组的地址
int main()
{
int arr[10]={0};
printf("%d,%d\n",arr,&arr);//两个值一样,意义不一样
//arr 数组首元素的地址&arr[0] &arr整个数组的地址
int *p=arr;
int(*p2)[10]=&arr;//与数组指针类型匹配
}
数组指针的使用
一维数组
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int (*p2)[10] = &arr;
printf("%d\n", *( (*p2)+2) );//arr[2] //*p2 == arr
return 0;
}
二维数组:
void print_arr(int (*arr)[5], int row, int col) {
int i = 0;
for(i=0; i<row; i++)
{
for(j=0; j<col; j++)
{
printf("%d ", arr[i][j]);
//*(*(arr+i)+j)
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行 arr+1类型 int(*)[5]
//可以数组指针来接收
print_arr(arr, 3, 5);
return 0;
}
数组传参:
一维数组
#include <stdio.h>
void test(int arr[])//ok
{}
void test(int arr[10])//ok
{}
void test(int *arr)//ok
{}
void test2(int *arr[20])//ok
{}
void test2(int **arr)//ok
{}
// arr2 首元素的地址 元素类型int *
//int *p; int**p1=&p;
int main()
{
int arr[10] = {0};
int *arr2[20] = {0};
test(arr);
test2(arr2);
}
二维数组
void test(int arr[3][5])//ok
{}
void test(int arr[][])//no
{}
void test(int arr[][5])//ok
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
void test(int *arr)//no 强转后可以传参
{}
void test(int* arr[5])//no
{}
void test(int (*arr)[5])//ok
{}
void test(int **arr)//no 二级指针接受一级指针的地址。
{}
int main()
{
int arr[3][5] = {0};
test(arr);
}
二维数组强转为一维数组传参
void Show(int *arr,int row,int col)
{
int i = 0,j = 0;
for(i = 0;i < row;i++)
{
for(j = 0;j < col;j++)
{
printf("%d ",arr[i*col+j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {0};
Show((int *)arr,3,5);
}
指针传参
一级指针接收:相应类型变量的地址,数组名
二级指针接收:相应一级指针的地址,指针数组
指针函数:返回指针的函数
函数名代表函数的地址
函数指针:指向函数代码首地址的指针变量。
函数指针就是指向函数的存储空间地址的指针。可以对函数指针进行赋值并且通过函数指针来调用函数。
void (*p) ()
(* (void (*)() ) 0) ( );
调用0地址处不带参数且返回值为void的函数
解析:
void(*)()函数指针类型
( void(*)() )0 将0强制转换为函数指针类型,0是一个地址,也就是说一个函数保存在首地址为0的一段区域内
*(void(*)() )0 取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数
(*(void(*)() )0)() 函数的调用。
void (* signal(int , void(*) (int) ) ) (int);
signal是一个函数,有两个参数,一个是int,一个是函数指针。
返回值是函数指针 void(*)(int)
void (* signal(int , void(*) (int) ) ) (int);代码简化 //也可以为 typedef void(*pFun)(int)
typedef void(*)(int) pFun;
pFun signal (int ,pFun);
void Function()
{
printf("Call Function!\n");
}
int main()
{
void(*p)();
*(int*)&p=(int)Function;
//&p 求p本身的地址,
//(int*)&p将地址强制转换为指向int类型数据的指针
//(int)Function 将函数的入口地址赋值给指针变量p
(*p)();//对函数指针的调用。
return 0;
}
使用函数指针的好处在于,可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期的维护,系统结构更加清晰。或归纳为便于分层设计、利于系统抽象、降低耦合度以及接口与实现分开。
函数指针数组:
char *(*pf[3])(char * p)
它是一个数组,数组名为pf,数组内存储了3个指向函数的指针。这些指针指向一些返回值类型为指向字符的指针,参数为一个指向字符的指针的函数。
用途:转移表
指向函数数组的指针:
char* (*(*pf)[3]) (char * p)
pf是一个指针,指向了一个包含了3个元素的数组;这个数组里面存的是指向函数的指针;这些指针指向一些返回值类型为指向字符的指针,参数为一个指向字符的指针的函数。
函数指针数组和指向函数数组的指针
使用实例
#include<stdio.h>
#include<string.h>
char * fun1(char *p)
{
printf("%s\n", p);
return p;
}
char * fun2(char *p)
{
printf("%s\n", p);
return p;
}
char * fun3(char *p)
{
printf("%s\n", p);
return p;
}
int main()
{
char *(*a[3])(char *p);
char *(*(*pf)[3])(char *p);
pf=&a;
a[0] = fun1;//可以直接用函数名
a[1] = &fun2;//可以用函数名加上取地址符
a[2] = fun3;
a[0]("fun1");
a[1]("fun2");
a[2]("fun3");
pf[0][0]("fun1");
pf[1][1]("fun2");
pf[2][2]("fun3");
return 0;
}