1.
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int a = 10;
int* p = &a;//一级指针
int** pp = &p;//二级指针
return 0;
}
上述代码中p的类型是int*
pp的类型是int**
2.int* arr[5];
数组arr的每个元素是整形指针
3.定义一个变量时,去掉变量名,剩下的就是变量的类型
4.用二级指针模拟二维数组:
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int arr1[5] = { 1,2,3,4,5 };//5列
int arr2[5] = { 2,3,4,5,6 };//5列
int arr3[5] = { 3,4,5,6,7 };//5列
int* arr[] = { arr1,arr2,arr3 };
int i = 0;
int j = 0;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 5; j++)
{
printf("%d ", *(arr[i] + j));
printf("%d ", arr[i][j]);
//上述两行代码等效
//因为arr[i][j] == *(arr + i)[j] == *(*(arr + i) + j)
}
printf("\n");
}
return 0;
}
5.char* p = "abcdef";
p存放的是首字符a的地址
6.可以把字符串想象为一个字符数组,但是这个数组是不能被修改的.
当常量字符串出现在表达式中的时候,他的值是第一个字符的地址.
例:
printf("%c", "abcdef"[3]);
char* p = "abcdef";
打印的是d,而且p[3] == "abcdef"[3];
7."abcdef" + 3拿到的是'd'的地址
8.数组指针和指针数组的区别示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int(*pa)[10] = &arr;//pa的类型是int(*)[10],p是一个指针,指向的是具有10个元素且每个元素的类型是int的数组
int a = 10;
int b = 20;
int c = 10;
int* p[3] = { &a,&b,&c };//pa的类型是int* [10],p是具有10个元素且每个元素的类型是int*的数组
return 0;
}
9.
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//&arr 的类型是int (*)[10]
10.*p == arr;
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int(*p)[10] = &arr;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < sz; i++)
{
printf("%d", arr[i]);
printf("%d", (*p)[i]);
//上述两行代码等效
//因为p == &arr
//所以*p == *&arr == arr
}
return 0;
}
11.数组名都是首元素的地址,二维数组也不例外
12.二维数组传参传过去的也是首元素的地址,那么就可以用数组指针来接受那个一维数组,这也就是二维数组传参的本质
13.二维数组解引用一次的的话是找到了一维数组,而此时一维数组是该一维数组的数组名,即该数组首元素的地址,再对它进行解引用就拿到了某个数据
14.可以这样再函数内部查看主函数内部的数组
arr,长度
例:
15.int (*)[10] == int [10]*
16.若parr是数组指针,则parr里面存的是这个数组的地址,解引用拿到的是首元素的地址
17.函数名同时也是函数名的地址,&函数名也一样
18.
#define _CRT_SECURE_NO_WARNINGS 1
#include
void print(int arr[3][5], int r, int c)
{
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
void(*p)(int[3][5], int, int) = &print;
return 0;
}
上述的p是函数指针变量
而int*p(int[3][5], int, int);是函数的声明
pf == print
*pf == print
上述的p也可以这样初始化:
void(*p)(int[3][5], int, int) = print;
19.使用函数指针的例子:转移表的创建:
#define _CRT_SECURE_NO_WARNINGS 1
#include
void menu()
{
printf("***********************\n");
printf("*****1.Add 2.Sub*****\n");
printf("*****3.Mul 4.Div*****\n");
printf("*****0.exit *****\n");
printf("***********************\n");
}
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
//x = (float)x;
return x / y;
}
int cal(int x, int y, int(*p)(int, int))
{
return p(x, y);
}
int main()
{
//函数指针数组
int(*p[5])(int, int) = { 0,Add,Sub,Mul,Div };//重点!!!
int input = 1;
menu();
scanf("%d", &input);
while (input != 0)
{
if (input <= 4)
{
int a = 0;
int b = 0;
printf("请输入两个数:\n");
scanf("%d %d", &a, &b);
printf("%d\n", cal(a, b, p[input]));
}
else
{
printf("输入错误!请重新输入\n");
}
menu();
scanf("%d", &input);
}
return 0;
}
20.(*(void (*)())0)();是调用地址为0的函数
21.void (* signal(int, void(*)(int) ) )(int);
这是一个函数的声明,函数名是signal,参数类型是(int, void(*)(int) ),返回类型是void (*)(int)
22.typedef可以将复杂的类型名字简单化
原名字还是可以用的
但是对于数组指针类型和函数指针类型就有点不一样
例:
#define _CRT_SECURE_NO_WARNINGS 1
#include
typedef int m;
typedef int(*parr)[10] ;
typedef int(*ppp)(int, int);
int Add(int x, int y)
{
return x + y;
}
int main()
{
m a = 10;
//上述代码等价于
//int a = 10;
int arr[10] = { 0 };
parr a = &arr;
//上述代码等价于
//int(*a)[10] = &arr;
ppp aaa = &Add;
//上述代码等价于
//int(*aaa)(int, int) = &Add;
return 0;
}