Hightlight
1. Review & summary
2. 指针数组&数组指针(指向数组的指针)
3.数组和字符串
4. 函数指针(指向函数的指针)
5. 堆分配内存 malloc函数
6. 堆分配内存其他相关函数:
6.1 calloc 函数
6.2 realloc 函数
1. Review & summary
1.1 指针作为形参
指针做为函数的形参 得到的是变量的地址 通过地址访问可以访问到原始变量 所以有机会修改到原始数据 (方法就是:对指针加*号 去操作数据)
1.2 常量指针和指针常量
禁止通过指针修改一个变量的值 (*号左边) const T*p
希望指针本身是只读的: T* const P
1.3 二级指针
保存指针地址, 二级指针一般用于函数的形参
1.4 void*
可以是任意类型的地址, 取得变量之前必须做强制类型转换!
1.5 指针数组: 保存一组指针
e.g. 命令行参数 int main(int argc, char* argv[])
2. 指针数组&数组指针(指向数组的指针)
2.1
int * p[5]; //p是个数组,每个元素是int*
int * p(double) //p是一个函数 形参是double 返回类型是int*
int(*P)[5]; //指向数组的指针,p是一个指针 指向5个元素的int数组
如何定义一个指向某种数组的指针:
e.g. char a [20][10] ====> char(*p)[20][10]
1 #include <stdio.h> 2 3 int main() 4 { 5 int *a[5]; //a是一个数组 5个元素 每个元素是int* 6 int* f(double); 7 int(*p)[5]; //p是一个指针 指向5个元素的int数组 8 9 int x[5]={11,22,33,44,55}; 10 int m; //m是一个int 变量 11 int* n; //n是一个指针,指向int变量 12 n=&m; //? 13 14 int y[6]={12,23,34,45,56,67}; 15 int z[8][5]; 16 17 p=&x; //p是一个指针 指向5个元素的数组 //p=&x 表示第一个元素的地址 18 19 return 0; 20 }
1 #include <stdio.h> 2 3 int main() 4 { 5 printf("abcxyz\n"); 6 printf("%p\n", "xyz"); 7 8 *"abc"=‘x‘; //字面值表示的字符串内容不可以修改, 导致core dump 9 return 0; 10 }
3.数组和字符串
1 #include <stdio.h> 2 int main() 3 { 4 char zi_fu_chuan[]="abc", xun_huan=0; 5 printf("sizeof(zi_fu_chuan) is %d\n",sizeof(zi_fu_chuan)); //等价于: char zi_fu_chuan[]={‘a‘,‘b‘,‘c‘,‘\0‘}; 6 for(xun_huan=0;xun_huan<=3;xun_huan++)
7 { 8 printf("%d ",zi_fu_chuan[xun_huan]); 9 printf("%c /n",zi_fu_chuan[xun_huan]); 10 } 11 printf("\n"); 12 return 0; 13 }
1 #include <stdio.h> 2 3 int main() 4 { 5 char * p_zi_fu_chuan = "abc"; 6 char zi_fu_chuan[3]="abc";//没有\0的数组不能当字符串使用 7 char zi_fu_chuan[]="abc"; 9 printf("%s\n", p_zi_fu_chuan); 10 printf("%s\n",zi_fu_chuan); 11 12 p_zi_fu_chuan=zi_fu_chuan; 13 printf("%s\n",p_zi_fu_chuan); 14 return 0; 15 16 }
安全读取字符串:
1 #include <stdio.h> 2 3 int main() 4 { 5 char zi_fu_chuan[10]; 6 //scanf("%s",zi_fu_chuan);//不安全 容易造成溢出 7 //gets(zi_fu_chuan); 8 fgets(zi_fu_chuan, 10, stdin); <-------------安全读取 9 printf("%s\n",zi_fu_chuan); 10 return 0; 11 }
字符串函数练习
strlen() strcat() strncat() strcpy() strcmp()
1 #include <stdio.h> 2 #include <string.h> 3 4 int main() 5 { 6 char zi_fu_chuan[20]="abc"; 7 char zi_fu_chuan_1[]="xyz"; 8 printf("length(strlen): %d\n", strlen(zi_fu_chuan)); 9 //strcat可能溢出, 使用strncat()避免溢出 10 printf("Merging(strcat): %s\n",strcat(zi_fu_chuan,zi_fu_chuan_1)); 11 12 printf("Merging(strncat): %s\n", strncat(zi_fu_chuan,zi_fu_chuan_1 ,3)); 13 //strcpy 可能溢出, 使用strncpy()避免溢出 14 printf("Coping(strcpy): %s\n",strcpy(zi_fu_chuan,zi_fu_chuan_1)); //比较两个字符串大小,前一个法则返回正,相等返回0,前一个小返回负数。可能溢出, 所以尽量使用strncmp来比较前几个字符 16 printf("Comparing(strcmp): %d\n", strcmp(zi_fu_chuan,"xyz")); 17 return 0; 18 }
Strcpy重写的练习
1 #include <stdio.h> 2 3 char * str_cpy(char *p_zi_fu_chuan, char * p_zi_fu_chuan_1){ 4 if(!p_zi_fu_chuan||!p_zi_fu_chuan_1){ //避免空指针 5 return p_zi_fu_chuan; 67 char *p = p_zi_fu_chuan; 8 while(*p_zi_fu_chuan_1!=0){ 9 *p_zi_fu_chuan = *p_zi_fu_chuan_1; 10 p_zi_fu_chuan++; 11 p_zi_fu_chuan_1++; 12 } 13 *p_zi_fu_chuan = ‘\0‘; 14 return p; 15 } 16 17 int main() 18 { 19 char zi_fu_chuan[10]="abc"; 20 printf("%s\n",str_cpy(zi_fu_chuan,"xy")); 21 return 0; 22 }
4. 函数指针(指向函数的指针)
4.1 程序中定义一个函数,编译时编译系统为函数代码分配一段内存,此段内存的起始位置称为函数指针。
4.2 定义
int(*p)(int,int); ==> p=max;
p++, p--等没有任何意义
e.g. 函数指针的用途:
用作比较的两个函数 仅仅只能通过修改代码的方式调用
1 #include <stdio.h> 2 #include <stdlib.h> 3 void pai_xu(int shu_zi[],int size){ 4 if(1==bi_jiao(&shu_zi[0],&shu_zi[1])) 5 { 6 shu_zi[0]=shu_zi[0]^shu_zi[1]; 7 shu_zi[1]=shu_zi[0]^shu_zi[1]; 8 shu_zi[0]=shu_zi[0]^shu_zi[1]; 9 } 10 } 11 12 int bi_jiao_1(const void * p_shu_zi_1, const void * p_shu_zi_2) 13 { 14 return (0 - bi_jiao(p_shu_zi_1,p_shu_zi_2)); 15 } 16 17 int bi_jiao(const void* p_shu_zi_1, const void* p_shu_zi_2){ 18 if(*(int*)p_shu_zi_1 > *(int*)p_shu_zi_2){ 19 return 1; 20 } 21 else if (*(int*)p_shu_zi_1 < *(int*)p_shu_zi_2){ 22 return -1; 23 } 24 else{ 25 return 0; 26 } 27 } 28 int main() 29 { 30 int shu_zi[2]={7,2}; 31 int i=0; 32 pai_xu(shu_zi,2); 33 for(i=0;i<(sizeof(shu_zi)/sizeof(shu_zi[0]));i++){ 34 printf("%d is %d\n",i,shu_zi[i]); 35 } 36 return 0; 37 }
如果想通过主函数调用来决定用哪一个函数那么就可以在排序函数里传递进一个比较函数的指针变量。
1 #include <stdio.h> 2 #include <stdlib.h> 3 void pai_xu(int shu_zi[],int size,int (*p_func) (const void*, const void*)){ //增加一个函数指针参数,调用函数时候传进哪个函数的指针就调用哪一个函数 4 if(1==p_func(&shu_zi[0],&shu_zi[1])) // 调用函数时候可以直接调用函数的指针 5 { 6 shu_zi[0]=shu_zi[0]^shu_zi[1]; 7 shu_zi[1]=shu_zi[0]^shu_zi[1]; 8 shu_zi[0]=shu_zi[0]^shu_zi[1]; 9 } 10 } 11 12 int bi_jiao_1(const void * p_shu_zi_1, const void * p_shu_zi_2) 13 { 14 return (0 - bi_jiao(p_shu_zi_1,p_shu_zi_2)); 15 } 16 17 int bi_jiao(const void* p_shu_zi_1, const void* p_shu_zi_2){ 18 if(*(int*)p_shu_zi_1 > *(int*)p_shu_zi_2){ 19 return 1; 20 } 21 else if (*(int*)p_shu_zi_1 < *(int*)p_shu_zi_2){ 22 return -1; 23 } 24 else{ 25 return 0; 26 } 27 } 28 int main() 29 { 30 int shu_zi[2]={7,2}; 31 int i=0; 32 pai_xu(shu_zi,2,bi_jiao); 33 for(i=0;i<(sizeof(shu_zi)/sizeof(shu_zi[0]));i++){ 34 printf("%d is %d\n",i,shu_zi[i]); 35 } 36 37 38 pai_xu(shu_zi,2,bi_jiao_1); //主函数调用过程中可以仅需要传入指定参数 39 for(i=0;i<(sizeof(shu_zi)/sizeof(shu_zi[0]));i++){ 40 printf("\n%d is %d\n",i,shu_zi[i]); 41 } 42 43 return 0; 44 }
4.3 C语言的qsort函数 (对任何数量数组进行排序)
将上面例子替换成qsort函数
1 #include <stdio.h> 2 #include <stdlib.h> 3 void pai_xu(int shu_zi[],int size,int (*p_func) (const void*, const void*)){ 4 if(1==p_func(&shu_zi[0],&shu_zi[1])) 5 { 6 shu_zi[0]=shu_zi[0]^shu_zi[1]; 7 shu_zi[1]=shu_zi[0]^shu_zi[1]; 8 shu_zi[0]=shu_zi[0]^shu_zi[1]; 9 } 10 } 11 12 int bi_jiao_1(const void * p_shu_zi_1, const void * p_shu_zi_2) 13 { 14 return (0 - bi_jiao(p_shu_zi_1,p_shu_zi_2)); 15 } 16 17 int bi_jiao(const void* p_shu_zi_1, const void* p_shu_zi_2){ 18 if(*(int*)p_shu_zi_1 > *(int*)p_shu_zi_2){ 19 return 1; 20 } 21 else if (*(int*)p_shu_zi_1 < *(int*)p_shu_zi_2){ 22 return -1; 23 } 24 else{ 25 return 0; 26 } 27 } 28 int main() 29 { 30 int shu_zi[2]={7,2}; 31 int i=0; 32 //pai_xu(shu_zi,2,bi_jiao); 33 qsort(shu_zi,2,sizeof(int),bi_jiao); //qsort只需要提供一个比较大小的函数即可 34 for(i=0;i<(sizeof(shu_zi)/sizeof(shu_zi[0]));i++){ 35 printf("%d is %d\n",i,shu_zi[i]); 36 } 37 38 39 //pai_xu(shu_zi,2,bi_jiao_1); 40 qsort(shu_zi,2,sizeof(int),bi_jiao_1); 41 for(i=0;i<(sizeof(shu_zi)/sizeof(shu_zi[0]));i++){ 42 printf("%d is %d\n",i,shu_zi[i]); 43 } 44 45 return 0; 46 }
5. 堆分配内存 malloc函数
--> 为了从对中分配变量使用函数malloc,需要一个参数指定序言分配的空间是多少个字节,它吧分配好的空间的首地址作为返回值。包含头文件 stdlib.h
--> malloc() 有可能失败,如果失败返回NULL。
--> 当使用完堆中的变量以后需要使用函数free, 把占用空间释放掉
--> free函数不会把原来指针中的地址设置为NULL,仅仅把空间释放掉。 释放掉后吧指针设置成空
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main() 5 { 6 //int shu_zi[3]={0},xun_huan=0; //分配在栈上 7 int * shu_zi=NULL, xun_huan=0; 8 (int*) malloc(3*sizeof(int)); //分配内存在堆上,从堆中分配3个整数变量 9 10 if(!shu_zi){ //如果返回空指针 说明malloc失败 所以每次malloc时候要做判断 11 printf("malloc failed \n"); 12 return 0; 13 } 14 15 for(xun_huan=0;xun_huan<3;xun_huan++){ 16 printf("please enter one number: \n"); 17 scanf("%d",shu_zi+xun_huan); 18 } 19 20 for(xun_huan=2;xun_huan>=0;xun_huan--){ 21 printf("%d",shu_zi[xun_huan]); 22 } 23 free(shu_zi); //释放 shu_zi =null; //释放之后要把指针变量设置成NULL 24 return 0; 25 }
6. 堆分配内存其他相关函数:
6.1 calloc 函数
calloc函数可以用于从堆中分配变量而且分配的变量都一定是被清0的
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main() 5 { 6 int * p_shu_zi = NULL, ge_shu=0,xun_huan; 7 p_shu_zi=(int*)malloc(3*sizeof(int)); //不保证变量都被清0 8 p_shu_zi= (int*)calloc(3,sizeof(int)); //保证所有变量都被清0 9 10 if(p_shu_zi){ 11 for(xun_huan=0;xun_huan<=2;xun_huan++){ 12 printf("%d\n", *(p_shu_zi+xun_huan)); 13 } 14 free(p_shu_zi); 15 p_shu_zi=NULL; 16 } 17 18 return 0; 19 } ~
6.2 realloc 函数
realloc(p_shu_zi,6*sizeof(int));
--> 第一个参数为原变量首地址, 第二个参数为要调整成多大
--> 如果原来的地址后面正好有空位 那么就会把后面内存加上
如果原来的地址后面没有空位那么久从新找6个int位 并且把原来的地址释放掉。
--> realloc 如果失败之后会返回NULL, 那么是否可以把原来指针直接付给realloc的返回值?
p_shu_zi= realloc(p_shu_zi,6*sizeof(int));
不可以这样, 如果调用失败的话那么p_shu_zi就为空,原来地址就泄露
--> 如果realloc的第二个参数为0, 效果类似free
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int main() 5 { 6 int * p_shu_zi = NULL, ge_shu=0,xun_huan; 7 //p_shu_zi=(int*)malloc(3*sizeof(int)); 8 p_shu_zi= (int*)calloc(3,sizeof(int)); 9 10 if(p_shu_zi){ 11 for(xun_huan=0;xun_huan<=2;xun_huan++){ 12 printf("%d\n", *(p_shu_zi+xun_huan)); 13 *(p_shu_zi+xun_huan)=xun_huan+1; 14 } 15 printf("\n\n"); 16 int *p_shu_zi_1=realloc(p_shu_zi,6*sizeof(int) );//把3个整数的空间调整为6个 17 if(p_shu_zi_1)//如果realloc成功 18 { 19 printf("%p %p \n", p_shu_zi, p_shu_zi_1); 20 p_shu_zi=p_shu_zi_1;//用新地址覆盖掉旧地址 21 22 for(xun_huan=0;xun_huan<=5;xun_huan++){ 23 printf(" %d \n", *(p_shu_zi+xun_huan)); 24 } 25 } 26 27 free(p_shu_zi); 28 p_shu_zi=NULL; 29 } 30 31 return 0; 32 }
6. 二维指针-续
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 void chai_fen(char* zi_fu_chuan, char **pp_zi_fu) 5 { 6 int i=0; 7 while(*(zi_fu_chuan+i)!=‘:‘){ 8 i++; 9 } 10 11 char *p_zi_fu=NULL; 12 p_zi_fu=(char*)malloc(i+1); 13 i=0; 14 while(*(zi_fu_chuan+i)!=‘:‘){ 15 *(p_zi_fu+i)=*(zi_fu_chuan+i); 16 i++; 17 } 18 *(p_zi_fu+i)=0; 19 *pp_zi_fu=p_zi_fu; 20 } 21 22 int main() 23 { 24 char zi_fu_chuan[]="1234:5678:9012"; 25 char *p_zi_fu=NULL; 26 27 chai_fen(zi_fu_chuan, &p_zi_fu); 28 printf("the result is : %s\n", p_zi_fu); 29 free(p_zi_fu); 30 p_zi_fu=NULL; 31 return 0; 32 }