1->字符指针
//1.字符指针 int?main() { char?arr[]?=?"abcdef"; char*?pc?=?arr; printf("%s\n",?arr); printf("%s\n",?pc); return?0; }
int?main() { const?char*?p?=?"abcdef";//"abcdef"是一个常量字符串 //指向元素a //*p?=?‘w‘; //printf("&c\n",*p); //printf("%s\n",?p); return?0; }
2->指针数组
//2.指针数组? // 是数组,用来存放指针的数组 int?main() { int?arr[10]?=?{?0?};//整形数组 char?ch[5]?=?{?0?};//字符数组 int*?parr[4];//存放整形指针的数组?-?指针数组 char?pch[5];//存放字符指针的数组?-?指针数组 return?0; }
int?main() { int?arr1[]?=?{?1,2,3,4,5?}; int?arr2[]?=?{?2,3,4,5,6?}; int?arr3[]?=?{?3,4,5,6,7?}; int*?parr[]?=?{?arr1,arr2,arr3?};//存首元素地址 int?i?=?0; for?(i?=?0;?i?<?3;?i++) { int?j?=?0; for?(j?=?0;?j?<?5;?j++) { printf("%d?",?*(parr[i]?+?j)); } printf("\n"); } return?0; }
3->数组指针
//3.数组指针 // 是指针 int?main() { int*?p?=?NULL;?//p是整形指针?-?指向整形的指针?-?可以存放整形的地址 char*?pc?=?NULL;?//pc是字符指针?=?指向字符的指针?-?可以存放字符的地址 //数组指针?-?指向数组的指针?-?存放数组的地址 int?arr[10]?=?{?0?}; //arr?-?首元素地址 //&arr[0]?-?首元素地址 //&arr?-?数组地址 int?arr[10]?=?{?1,2,3,4,5,6,7,8,9,10?}; int(*p)[10]?=?&arr;?//方块优先级高 //上面的p就是数组指针 return?0; }
int?main() { int?arr[10]?=?{?1,2,3,4,5,6,7,8,9,10?}; int(*pa)[10]?=?&arr; int?i?=?0; for?(i?=?0;?i?<?10;?i++) { printf("%d?",?(*pa)[i]);?//*pa?==?arr } return?0; }
int?main() { int?arr[3][5]?=?{?{1,2,3,4,5},{2,3,4,5,6?},{3,4,5,6,7}?}; print1(arr,?3,?5);//arr?-?数组名就是首元素地址 //把arr想象成一维数组 //所以数组arr有三个元素,首元素地址就是第一行地址 print2(arr,?3,?5); return?0; }
int?arr[5];??????????//??? int*?parr1[10];??????//parr1是一个数组,数组有10个元素,每个元素都是一个int型指针,?int*?parr1[10]是指针数组 int?(*parr2)[10]; ???//parr2是一个指针,该指针指向的了一个数组,数组有10个元素,每个元素是int型,int?(*parr2)[10]是数组指针 int?((*parr3)[10])[5];? //parr3是一个数组,该数组有10个元素,每个元素是一个数组指针,该数组指针指向的数组有五个元素,每个元素是int
4->数组参数、指针参数
//4.数组参数、指针参数 //一维数组传参 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? {} int?main() { int?arr[10]?=?{?0?}; int?*arr2[20]?=?{?0?}; test(arr); test2(arr2); return?0; }
//二维数组传参 void?test(int?arr[3][5]) {} void?test2(int?arr[][5]) {} void?test3(int?arr[3][])?//err,不能省略列 {} void?test4(int*?arr)?//err,传过来的是一行数组?不能用int* {} void?test5(int?**arr)//err,二级指针也不能接收?一个数组地址 {} void?test6(int?(*arr)[5]) {} int?main() { int?arr[3][5]?=?{?0?}; test(arr);//二维数组传参 test2(arr); test3(arr); test4(arr); test5(arr); test6(arr); return?0; } //总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。 //因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素 //这样才方便运算 //二级指针传参 void?test(int**??ptr) { printf("num?=?%d\n",?**ptr); } int?main() { int?n?=?10; int*?p?=?&n; int**?pp?=?&p; test(pp); test(&p); return?0; }
5->函数指针
//5.函数指针?-?是指向函数的指针?-?存放函数地址的一个指针 int?Add(int?x,?int?y) { int?z?=?0; z?=?x?+?y; return?z; } int?main() { int?a?=?10; int?b?=?20; int?arr[10]?=?{?0?}; int?(*p)[10]?=?&arr; //printf("%d\n",?Add(a,?b)); //&函数名?和?函数名?都是函数的地址? /* printf("%p\n",?&Add); printf("%p\n",?Add); */ int??(*pa)(int,?int)?=?Add;?//函数指针 printf("%d\n?",?(*pa)(2,?3)); return?0; } void?Print(char*str) { printf("%s\n",?str); } int?main() { void?(*p)(char*)?=?Print;? (*p)("hello?bit"); return?0; }
//分析代码1 (*(void?(*)())0)(); void(*)()?-?函数指针类型 把0强制类型转换成:void(*)()?-?0就是一个函数的地址 调用0地址处的该函数 //代码2 void?(*signal(int,?void(*)(int)))(int); void(*??)(int); signal(int,?void(*)(int))? signal是一个函数声明?-?参数有两个,一个是int,第二个是函数指针,该函数指针指向的函数的参数是int,返回类型是void signal函数的返回类型也是个函数指针:?该函数指针指向的函数的参数是int,返回类型是void
int?Add(int?x,?int?y) { int?z?=?0; z?=?x?+?y; return?z; } int?main() { int?a?=?10; int?b?=?20; int??(*pa)(int,?int)?=?Add;?//函数指针 //以下三种都正确 printf("%d\n?",?(*pa)(2,?3)); printf("%d\n?",?pa(2,?3)); printf("%d\n?",?Add(2,?3)); return?0; }
6->函数指针数组
//6.函数指针数组?-?存放函数的地址的数组 ? 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) { return?x?/?y; } int?main() { //指针数组 int*?arr[5]; //需要一个数组,这个数组可以存放4个函数的地址?-?函数指针的数组 int?(*pa)(int,?int)?=?Add;?//Sub/Mul/Div int?(*parr[4])(int,?int)?=?{Add,Sub,?Mul,Div};//函数指针的数组 int?i?=?0; for?(i?=?0;?i?<?4;?i++) { printf("%d\n",parr[i](2,?3)); } return?0; }
//测试题 char*?my_strcpy(char*?dest,?const?char*?src); //1.写一个函数指针?pf,能够指向my_strcpy char*?(*pf)(char*,?const?char*); //2.写一个函数指针数组pfArr,?能够存放4个my_strcpy函数的地址 char*?(*pfArr[4])(char*,?const?char*);
//函数指针案例 //计算器 void?menu() { printf("1.add\n2.sub\n3.Mul\n4.div\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) { return?x?/?y; } int?Div(int?x,?int?y) { return?x?^?y; } int?main() { int?input?=?0; int?x?=?0; int?y?=?0; do { menu(); printf("请选择:>"); scanf("%d",&input); switch(input) { case?1: printf("请输入两个操作数:>"); scanf("%d%d",?&x,?&y); printf("%d\n",?Add(x,?y)); break; case?2: printf("请输入两个操作数:>"); scanf("%d%d",?&x,&y); printf("%d\n",?Sub(x,?y)); break; case?3: printf("请输入两个操作数:>"); scanf("%d%d",?&x,?&y); printf("%d\n",?Mul(x,?y)); break; case?4: printf("请输入两个操作数:>"); scanf("%d%d",?&x,?&y); printf("%d\n",?Div(x,?y)); break; case?0: printf("退出\n"); break; default: printf("选择错误\n"); break; } }?while?(input); } //方法2.利用函数指针数组 void?menu() { printf("1.add\n2.sub\n3.Mul\n4.div\n5.Xor"); } 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) { return?x?/?y; } int?Xor(int?x,?int?y) { return?x?^?y; } int?main() { int?input?=?0; int?x?=?0; int?y?=?0; //pfArr?是一个函数指针数组?-?用途:转移表 int?(*pfArr[])(int,?int)?=?{?0,Add,Sub,Mul,Div,Xor}; do { menu(); printf("请选择:>"); scanf_s("%d",?&input); if?(input?>=?1?&&?input?<=?5) { printf("请输入操作数:>"); scanf_s("%d%d",?&x,?&y); int?ret?=?pfArr[input](x,?y); printf("%d\n",?ret); } else?if?(input?==?0) { printf("退出\n"); } else { printf("选择错误!\n"); } }?while?(input); }
7->指向函数指针数组的指针
//7.指向函数指针数组的指针 int?Add(int?x,?int?y) { return?x?+?y; } int?main() { int?arr[10]?=?{?0?}; int?(*p)[10]?=?&arr;?//取出数组的地址 int?(*pfArr[4])(int,?int);//pfArr?-?是一个数组?-函数指针的数组 //ppfArr是一个指向?函数指针数组?的指针 int(*(*ppfArr)[4])(int,?int)?=?&pfArr;? // //ppfArr?是一个数组指针,指针指向的数组有4个元素 //指向的数组的每个元素的类型是一个函数指针?int(*)(int,?int) // return?0; }
8->回调函数
//8.回调函数?-?通过函数指针调用的函数 void?print(const?char?*str) { printf("hehe:%s",?str); } void?test(void?(*p)(char*)) { printf("test\n"); p("bit"); } int?main() { test(print); return?0; }
//void类型的指针 int?main() { int?a?=?10; //int*?pa?=?&a; //char*?pc?=?&a; //char?ch?=?‘w‘; void*?p?=?&a;?//无类型指针?-?可以接收任意类型的地址?-?不能进行解引用操作?-?不能进行加减整数的操作 p?=?&ch; return?0; }
//qsort?-?库函数?-?排序?-?可以排序任意类型的数据? //quick?sort //void?qsort( // void*?base,??//目标数组首元素地址 // size_t?num, ?//待排序数组元素个数 // size_t?width,?//每个元素的大小-单位是字节 // int?(*cmp)(const?void*?e1,?const?void*?e2)?//函数指针,比较两个元素的所用函数的地址?-?这个函数使用者自己实现?-?函数指针的两个参数是:待比较的两个元素的地址 //); //对arr进行排序,排成升序 //冒泡排序函数只能排序整形数组 //bubble_sort(arr,?sz);//冒泡排序函数? //void?bubble_sort(int?arr[],?int?sz) { //确定冒泡排序的趟数 int?i?=?0; for?(i?=?0;?i?<?sz?-?1;?i++) { int?flag?=?1;//假设这一趟要排序的数据已经有序? //每一趟冒泡排序 int?j?=?0; for?(j?=?0;?j?<?sz?-?1?-?i;?j++) { if?(arr[j]?>?arr[j?+?1]) { int?tmp?=?arr[j]; arr[j]?=?arr[j?+?1]; arr[j?+?1]?=?tmp; flag?=?0; } } if?(flag?==?1) { break; } } } struct?stu { char?name[20]; int?age; }; int?cmp_int(const?void*?e1,?const?void*?e2)?//void*?-?可以接收任意类型的地址 { //比较两个整形值的 return?*(int*)e1?-?*(int*)e2; } int?cmp_float(const?void*?e1,?const?void*?e2) { //比较两个浮点型 return?((int)(*(float*)e1?-?*(float*)e2)); } int?cmp_stu_by_age(const?void*?e1,?const?void*?e2) { //比较两个年龄 return?((struct?stu*)e1)->age?-?((struct?stu*)e2)->age; } int?cmp_stu_by_name(const?void*?e1,?const?void*?e2) { //比较名字就是比较字符串 //字符串比较不能直接用><=来比较,应该用strcmp函数 return?strcmp(((struct?Stu*)e1)->name?,((struct?Stu*)e2)->name); } void?test1() { int?arr[10]?=?{?9,8,7,6,5,4,3,2,1,0?}; int?sz?=?sizeof(arr)?/?sizeof(arr[0]); qsort(arr,?sz,?sizeof(arr[0]),?cmp_int); int?i?=?0; for?(i?=?0;?i?<?sz;?i++) { printf("%d?",?arr[i]); } } void?test2() { float?f[]?=?{?9.0,?8.0,?7.0,?6.0,?5.0,?4.0?}; int?sz?=?sizeof(f)?/?sizeof(f[0]); qsort(f,?sz,?sizeof(f[0]),?cmp_float); int?i?=?0; for?(i?=?0;?i?<?sz;?i++) { printf("%f?",?f[i]); } } void?test3() { struct?stu?s[3]?=?{?{"zhangsan",20},{"lisi",30},{"wangwu",10}?}; int?sz?=?sizeof(s)?/?sizeof(s[0]); qsort(s,?sz,?sizeof(s[0]),?cmp_stu_by_age); int?i?=?0; for?(i?=?0;?i?<?sz;?i++) { printf("%d?",?s[i]); } } void?test4() { struct?stu?s[3]?=?{?{"zhangsan",20},{"lisi",30},{"wangwu",10}?}; int?sz?=?sizeof(s)?/?sizeof(s[0]); qsort(s,?sz,?sizeof(s[0]),?cmp_stu_by_name); int?i?=?0; for?(i?=?0;?i?<?sz;?i++) { printf("%s?",?s[i]); } } //实现bubble_sort函数的程序员,他是否知道未来排序的数据类型-不知道 //那程序员也不知道,待比较的两个元素的类型 void?Swap(char*?buf1,?char*?buf2,?int?width) { int?i?=?0; for?(i?=?0;?i?<?width;?i++) { char?tmp?=?*buf1; *buf1?=?*buf2; *buf2?=?tmp; buf1++; buf2++; } } void??bubble_sort(void*?base,?int?sz,?int?width,?int?(*cmp)(const?void*?e1,?const?void*?e2)) { int?i?=?0; for?(i?=?0;?i?<?sz?-?1;?i++) { //每一趟冒泡排序 int?j?=?0; for?(j?=?0;?j?<?sz?-?1?-?i;?j++) { //两个元素的比较 if?(cmp((char*)base+j*width,(char*)base+(j+1)*width)?>?0) { //交换 Swap((char*)base?+?j?*?width,?(char*)base?+?(j?+?1)?*?width,?width); } } } } int?cmp_stu_by_age(const?void*?e1,?const?void*?e2) { //比较两个年龄 return?((struct?stu*)e1)->age?-?((struct?stu*)e2)->age; } void?test5() { struct?stu?s[3]?=?{?{"zhangsan",20},{"lisi",30},{"wangwu",10}?}; int?sz?=?sizeof(s)?/?sizeof(s[0]); //使用bubble_sort的程序员一定知道自己排序的是什么数据 //就应该知道如何比较待排序数组中的元素 bubble_sort(s,?sz,?sizeof(s[0]),cmp_stu_by_age); } int?main() { ?? //通过qsort排序 test1();?//排序整型数组 test2();?//排序浮点型数组 test3();?//排序-?通过结构体数组的年龄 test4();?//排序-?通过结构体数组的名字 test5();?//仿照qsort来修改冒泡函数实现能够排序任意类型 return?0; }
9->指针和数组面试题的解析
//9.指针和数组面试题的解析 int?main() { //数组名是首元素地址 //例外 //1.sizeof(数组名)?-?数组名表示整个数组 //2.&数组名?-?数组名表示整个数组 ??// //一维数组 int?a[]?=?{?1,2,3,4?}; printf("%d\n",?sizeof(a));????//sizeof(数组名)?-?计算的是数组总大小?-?单位是字节?-16 printf("%d\n",?sizeof(a?+?0));//?4/8?-?数组名这里表示首元素的值,a+0还是首元素地址,地址的大小就是4/8个字节 printf("%d\n",?sizeof(*a));???//4?-?数组名表示首元素地址,*a就是首元素 printf("%d\n",?sizeof(a?+?1));//?4/8?-?第二个元素的地址,地址的大小就是4/8个字节 printf("%d\n",?sizeof(a[1]));?//4?-?第2个元素的大小 printf("%d\n",?sizeof(&a));???//?4/8?-?&a取出的是数组的地址,但是数组地址那也是地址,地址的大小就是4/8个字节 printf("%d\n",?sizeof(*&a));??//16 printf("%d\n",?sizeof(&a?+?1));?//?4/8 printf("%d\n",?sizeof(&a[0])); //?4/8 printf("%d\n",?sizeof(&a[0]?+?1));//?4/8 return?0; }
//字符数组 int?main() { char?arr[]?=?{?‘a‘,‘b‘,‘c‘,‘d‘,‘e‘,‘f‘?}; printf("%d\n",?sizeof(arr));; //6 printf("%d\n",?sizeof(arr?+?0));//?4/8 printf("%d\n",?sizeof(*arr));???//?1 printf("%d\n",?sizeof(arr[1]));?//1 printf("%d\n",?sizeof(&arr)); //4/8 printf("%d\n",?sizeof(&arr?+?1));?//?4/8 printf("%d\n",?sizeof(&arr[0]?+?1));?//?4/8 printf("%d\n",?strlen(arr)); //?随机值 printf("%d\n",?strlen(arr?+?0));//?随机值 //printf("%d\n",?strlen(*arr));???//?err //printf("%d\n",?strlen(arr[1]));?//?err printf("%d\n",?strlen(&arr)); //?随机值 printf("%d\n",?strlen(&arr?+?1));?//随机值-6 printf("%d\n",?strlen(&arr[0]?+?1));?//随机值-1 return?0; } int?main() { char?arr[]?=?"abcdef"; printf("%d\n",?sizeof(arr)); //?7?? printf("%d\n",?sizeof(arr?+?0));//?4/8 printf("%d\n",?sizeof(*arr)); //1 printf("%d\n",?sizeof(arr[1]));?//1 printf("%d\n",?sizeof(&arr));???//?4/8 printf("%d\n",?sizeof(&arr?+?1));//?4/8 printf("%d\n",?sizeof(&arr[0]?+?1));//?4/8 printf("%d\n",?strlen(arr)); //?6 printf("%d\n",?strlen(arr?+?0));//?6 //printf("%d\n",?strlen(*arr)); //err //printf("%d\n",?strlen(arr[1]));?//err printf("%d\n",?strlen(&arr));???//?6 printf("%d\n",?strlen(&arr?+?1));//随机值 printf("%d\n",?strlen(&arr[0]?+?1));//?5 return?0; } int?main() { const?char*?p?=?"abcdef"; printf("%d\n",?sizeof(p)); //?4/8 printf("%d\n",?sizeof(p?+?1)); //?4/8 printf("%d\n",?sizeof(*p)); //?1 printf("%d\n",?sizeof(p[0])); //?1 p[0]?==?*(p?+?0)?==?‘a‘ printf("%d\n",?sizeof(&p)); //?4/8 printf("%d\n",?sizeof(&p?+?1)); //?4/8 printf("%d\n",?sizeof(&p[0]?+?1));//?4/8 printf("%d\n",?strlen(p)); //?6 printf("%d\n",?strlen(p?+?1)); //?5 //printf("%d\n",?strlen(*p)); //?err //printf("%d\n",?strlen(p[0])); //?err p[0]?==?*(p?+?0)?==?‘a‘ printf("%d\n",?strlen(&p)); //?随机值 printf("%d\n",?strlen(&p?+?1)); //?随机值 printf("%d\n",?strlen(&p[0]?+?1));//?5 return?0; }
//二维数组 int?main() { int?a[3][4]?=?{?0?}; printf("%d\n",?sizeof(a));?//?48 printf("%d\n",?sizeof(a[0][0]));//4 printf("%d\n",?sizeof(a[0]));???//16??a[0]相当于第一行做为一维数组的数组名?==?sizeof(数组名) ? printf("%d\n",?sizeof(a[0]?+?1));//?4/8?a[0]是第一行首元素地址?a[0]+1,第一行第二个元素的地址 printf("%d\n",?sizeof(*(a[0]?+?1)));//4 printf("%d\n",?sizeof(a?+?1));???//4/8??a是二维数组的首元素地址,而二维数组的首元素是第一行,及把二位数组看作了一维数组,a+1就是第二行的地址 printf("%d\n",?sizeof(*(a?+?1)));//16 printf("%d\n",?sizeof(&a[0]?+?1));//4/8?第二行地址 printf("%d\n",?sizeof(*(&a[0]?+?1)));//16 printf("%d\n",?sizeof(*a));?//16?*a?=?第一行地址解引用 printf("%d\n",?sizeof(a[3]));?//16?表示第四行,sizeof不参与真实计算 return?0; }
//指针笔试题 int?main() { int?a[5]?=?{?1,2,3,4,5?}; int*?ptr?=?(int*)(&a?+?1);?//&a?+?1?为5后面的地址 printf("%d,?%d\n",?*(a?+?1),?*(ptr?-?1));?//2?5?? return?0; } struct?Test { int?Num; char*?pcName; short?sDate; char?cha[2]; short?sBa[4]; }*p;?//结构体指针?p //假设p?的值为ox100000,如下表表达式的值分别为多少? //已知,?结构体Test类型的变量大小是20个字节 int?main() { p?=?(struct?Test*)0x100000; printf("%p\n",?p?+?0x1);??//0x00100014? printf("%p\n",?(unsigned?long)p?+?0x1);?//0x00100001 printf("%p\n",?(unsigned?int*)p?+?0x1);?//0x00100004 return?0; } ? int?main() { int?a[4]?=?{?1,2,3,4?}; int*?ptr1?=?(int*)(&a?+?1); int*?ptr2?=?(int*)((int)a?+?1); printf("%x,%x",?ptr1[-1],?*ptr2);//?4?0x02000000 return?0; } int?main() { int?a[3][2]?=?{?(0,1),(2,3),(4,5)?};//逗号表达式?1,3,5 int*?p; p?=?a[0];?//第一行?1,?3 printf("%d",?p[0]);?//1? return?0; } int?main() { int?a[5][5]; int(*p)[4]; p?=?a;//int?(*)[4]?----?int?(*)[5] printf("%p,%d\n",?&p[4][2]?-?&a[4][2],?&p[4][2]?-?&a[4][2]);//0xfffffffc?,?4 return?0; } int?main() { int?aa[2][5]?=?{?1,2,3,4,5,6,7,8,9,10?}; int*?ptr1?=?(int*)(&aa?+?1); int*?ptr2?=?(int*)(*(aa?+?1));?//*(aa?+?1)?==?aa[1] printf("%d,%d\n",?*(ptr1?-?1),?*(ptr2?-?1));?//?10?5 return?0; } int?main() { char*?a[]?=?{?"work","at","alinbaba"?}; char**?pa?=?a; pa++; printf("%s\n",?*pa);//at return?0; }
原文:https://blog.51cto.com/u_15157811/2833720