Hightlight
1.1 自我理解的指针概念
1.2 如果用不同类型的数据来赋值指针
1.3 野指针
1.4 悬空指针
1.5 地址(指针)作为参数
1.6 数组作为形参
1.7 常量指针和指针常量
1.8 举例: 排序一组数据 数据都是const类型 不能改变数据的情况下排序
1.9 主方法参数
1.10 strcmp()函数
1.11 二级指针
1.12 Void* 类型
1.13 Assignment
1. 指针基本知识
1.1 自我理解的指针概念
保存地址的变量叫指针
指针作为数据用的时候 指针就是地址
1.2 如果用不同类型的数据来赋值指针
1 #include <stdio.h> 2 3 int main(){ 4 char x[8]={‘a‘,‘b‘,‘c‘,‘d‘,‘e‘,‘f‘,‘g‘}; 5 char* p1=&x[0]; 6 char* p2=&x[2]; 7 int * p3=&x[3]; 8 printf("%X\n",*p3); 9 return 0; 10 }
产生警告信息
*p3的打印结果 其实是从d到g的int值
|a|b|c|d|e|f|g|h|.....
^ ^
|<- P3->|
1.3 野指针
野指针 没有赋值的指针
避免野指针 任何定以后的指针都加等号=去赋值
0的特殊含义
---> ‘\0’
---> 逻辑判断里的假
---> 用在指针里表示空地址 0 =NULL
1 #include <stdio.h> 2 3 int main() 4 { 5 int a[5]={11,22,33,44,55}; 6 int *p; //野指针,尽量避面,用空指针代替 7 printf("%p\n",p); 8 printf("%d\n",(3>5)); 9 int *q =0; //初始化指针为空指针 10 printf("%p\n",q); 11 /*****************************************************/ 12 //打印指针的每一个字节 13 #define T int * 14 union { 15 T x; 16 char b[sizeof(T)]; 17 }u; 18 u.x=q; 19 int i; 20 for(i=0;i<sizeof(T);i++) 21 { 22 printf("%d ",u.b[i]); 23 } 24 printf("\n"); 25 *p=100; //访问野指针 可能引发segmentation fault 26 27 p=a; //数组当做数据用的时候表示第一个元素的地址 28 /*****************************/ 29 for(i=0;i<5;i++) 30 printf("%d ",a[i]); 31 printf("\n"); 32 33 for(i=0;i<5;i++) 34 printf("%d ",*(a+i)); //数组名加上一个下标加上一个整数 就是以那个整数为下表的元素的地址 //数组名加几就表示以几位下表元素的地址 35 printf("\n"); 36 37 for(i=0;i<5;i++) printf("%d ",p[i]);printf("\n"); // 11 22 33 44 55 38 39 for(i=0;i<5;i++) printf("%d ",*(p+i)); printf("\n"); // 11 22 33 44 55 40 41 for(i=0;i<5;i++) printf("%d ",*p+i); printf("\n"); // 11 12 13 14 15 42 43 for(i=0;i<5;i++) printf("%d ",*p++); printf("\n"); // 11 22 33 44 55 44 45 for(i=0;i<5;i++) printf("%d ",p[i]); printf("\n"); //-1081417716 1 0 0 -712421632 11 22 33 44 55 p P 46 47 for(i=-5;i<0;i++) printf("%d ",p[i]); printf("\n"); // 11 22 33 44 55 48 49 for(i=0;i++;i<5) printf("%d ", *p--); printf("\n"); // -1079573188 55 44 33 22 50 for(i=0;i<5;i++) printf("%d ", *--p); printf("\n"); // 55 44 33 22 11 51 return 0; 52 }
数组指针用法:
p[i] = *[p+i] ==*p++ (但是之后的指针移动到最后一次++的位置)
p[i-1] = *p--
1.4 悬空指针
保存了可能已经消失的地址的指针 成为悬空指针
不要返回不通局部变量的地址 除非加上static
1 #include <stdio.h> 2 3 char* func() 4 { 5 char a=‘#‘; 6 return &a; //返回局部变量指针 Warning! // 保存了可能已经消失的地址的指针 成为悬空指针 除非加上static 7 } 8 9 int main() 10 { 11 char c=‘@‘; 12 char *p =&c; 13 *p=‘S‘; 14 printf("c=%c\n",c); 15 printf("*p=%c\n",*p); 16 p=func(); //指向一个可能已经不存在的地方(或者是释放过的地方) 17 printf("*p=%c\n",*p); 18 return 0; 19 }
1.5 地址(指针)作为参数
注意1:指针本身并不是关注本身,所以指针在使用时 基本都要到*号
想要目标单位交换时候 要操作目标本身 而不是指针。
1 #include <stdio.h> 2 3 int main() 4 { 5 int a=10, b=20; 6 // int* p=&a, q=&b; //需要注意q是int类型 编译报错 7 int x,y[5],*p=&a, *q=&b; 8 //int t=a;a=b;b=t; 9 int t=*p;*p=*q;*q=t; 10 printf("%d, %d\n",a,b); 11 12 int m=10, n=20; 13 int* u=&m, *v=&n; 14 int *w=u;u=v;v=w; 15 printf("%d, %d\n",m ,n); // 为何m,n的值不变? 要想目标发生变化需要操作目标本身 而不是指针。 //int *w=u(&m); u=v(&n); v=w(&m); 其实是指针w和v交换了 但是目标m和n没有交换。 16 17 return 0; 18 }
c语言里面参数传递永远是值传递
--->f2()传递的是地址 地址传递
1 #include <stdio.h> 2 3 void f1(int *p, int *q){ 4 int *t=p;p=q;q=t; 5 } 6 7 void f2(int* p,int *q){ 8 int t=*p;*p=*q;*q=t; 9 } 10 11 void f3(int a, int b){ 12 int t=a;a=b;b=t; 13 } 15 int main() 16 { 32 printf("aa=%d, bb=%d\n",aa,bb); 33 f1(&aa,&bb);printf("f1()---> aa=%d, bb=%d\n",aa,bb); 34 35 f2(&aa,&bb);printf("f2()---> aa=%d, bb=%d\n",aa,bb); 36 37 f3(aa,bb);printf("f3()---> aa=%d, bb=%d\n",aa,bb); 38 return 0; 39 }
1.6 数组作为形参
---当数组做为形参时候 其实传递的是数组首地址的指针~
任何类型的指针计算sizeof都是4个字节
1 #include <stdio.h> 2 3 show(double a[], int n) 4 { 5 double x=123.45; 6 printf("sizeof[a]=%d\n",sizeof(a)); //a其实是一个指针 输出结果为4 7 a=&x; 8 printf("*a=%g\n",*a); 9 } 10 11 void print(double *p, int n) 12 { 13 int i; 14 for(i=0;i<n;i++){ 15 printf("a[%d]=%g ",i,*(p+i)); //*(p+i))==p[i] 16 }printf("\n"); 17 } 18 19 int main() 20 { 21 double a[5]={1,2,3,4,5}; 22 show(a,5); 23 print(a,5); 24 25 char al[3]={‘a‘,‘b‘,‘c‘}; 26 printf("sizeof[al]=%d\n",sizeof(al)); \\al是一个数组 所以大小是3 有3个char类型的变量在al数组里 27 char *t=&al[0]; 28 printf("sizeof(t)=%d\n",sizeof(t)); \\ 这里问的仅仅是t这个指针的sizeof值 任何指针的sizeof都是4 29 30 return 0; 31 }
1.7 常量指针和指针常量
----> 字符串: 从指定位置开始 以空字符“\0”结束的字符数组。
----> const char *p (或者 char const* p)
不会通过指针修改数据,指针p保存字符常量的地址
----> char * const r =a+1;
r是一个const类型的指针 所指向的内容可以修改 但是指针本身不能修改 必须初始化
1 #include <stdio.h> 2 3 int main() 4 { 5 char a[100]={‘h‘,‘e‘,‘\0‘,‘w‘,‘o‘}; //如果把字符数组当做字符串来使用的话 只到反斜杠0 6 //"csd1007" 这样一个字符串其实是在只读存储区里保存一个8个字节的char类型 // const char[8]={‘c‘,‘s‘,‘d‘,‘1‘,‘0‘,‘0‘,‘7‘,‘\0‘} 7 puts(a); //输出缓冲区遇到反斜杠0之后就结束 8 puts("csd1007"); 10 char* p=a; 11 printf("%c\n",*p); 12 *p=‘w‘; 13 puts(a); 14 15 p="csd1007"; 16 printf("%c\n",*p); 17 18 *p=‘w‘; //修改const类型数据,导致运行的core dump 19 const char* q=NULL; // q是保存字符常量, 指针q所指的字符目标当做常量 不会通过指针修改目标的数据 20 q="csd1007"; //只是把字符串的首地址赋值给指针, 并不是复制字符串 21 *q=‘w‘; // 编译报错 22 24 p=a; 25 strcpy(a,"NB"); 26 puts(p); 27 28 q=a+3; // 29 puts(q); 30 31 char* const r=a+1; //r是一个const类型的指针 所指向的内容可以修改 但是指针本身不能修改 32 //r=a; //编译错误 33 puts(a); 34 *r=‘A‘; 35 puts(a); 36 // 危险代码如下 37 char * str; //str首先是野指针 38 scanf("%s",str); // scanf把输入的数据的地址放到str去, 如果str是const类型 可能导致段错误 39 strcpy(str,"hello"); // 同上 40 return 0; 41 }
1.8 例子: 排序一组数据 数据都是const类型 不能改变数据的情况下排序
-->通常指针只能保存地址 地址也只能被指针来保存
-->数组名仅仅表示起始地址
1 #include <stdio.h> 2 3 int main() 4 { 5 char* names[9]={"Hejunjun","yangYong","WangGang","LongWang","SSSS5555","SSS666","77","888","9999"}; 6 7 int i; 8 for(i=0;i<9;i++){ 9 printf("welcome the following guys %s\n",*(names+i)); 10 } 11 /*数组不变的情况下排序*/ 12 const int a=10,b=80,c=20,d=60,e=98,f=76; 13 const int * p[6]={&a,&b,&c,&d,&e,&f}; 14 int j; 15 for(i=0;i<6;i++){ 16 for(j=i+1;j<6;j++){ 17 if(*p[j]<*p[i]){ 18 const int * t=p[j];p[j]=p[i];p[i]=t; 19 } 20 } 21 } 22 for(i=0;i<6;i++){ 23 printf("%d\n",*p[i]); 24 } 25 26 return 0; 27 }
1.9 主方法参数
int main(int argc,char* argv[])
argc--> 一共几个字符串
char* argv[] --> 存每个字符串的首地址
1.10 strcmp()函数
atoi()
atof();
strcmp();
1.11 二级指针
保存指针的地址的变量 称为二级指针
需要简介修改指针的值,需要修改指针的指向的时候
1 #include <stdio.h> 2 3 int main() 4 { 5 char c; 6 char* pc; 7 int n; 8 int * pn; 9 short s; 10 short* ps; 11 double d=1.23; 12 double * pd=&d; 13 double** pp=&pd; 14 15 printf("&c=%p\n",&c); 16 printf("&pc=%p\n",&pc); 17 printf("&n=%p\n",&n); 18 printf("&pn=%p\n",&pn); 19 printf("&s=%p\n",&s); 20 printf("&ps=%p\n",&ps); 21 printf("&d=%p\n",&d); 22 printf("&pd=%p\n",&pd); 23 printf("&pp=%p\n",&pp); //pp是一个指向double* 变量的指针 24 25 return 0; 26 }
一个数字字符减去字符0 (‘0’), 就得到数字 ‘3’-‘0’=3
一个数字加上字符0 (‘0’), 就得到数字字符
1 #include <stdio.h> 2 #include <ctype.h> 3 4 int str2int(const char* str, const char** q) //2级指针,想改变p的位置 5 { 6 int r=0; 7 while(isdigit(*str)){ 8 r=r*10+*str-‘0‘; 9 ++str; 10 } 11 *q=str; 12 return r; 13 } 14 15 int main() 16 { 17 const char* p=NULL; 18 int n= str2int("3926abxys",&p); 19 printf("number=%d, p=%s\n",n,p); 20 return 0; 21 }
1.12 Void* 类型
1 #include <stdio.h> 2 3 void showbyte(void* addr, int byte) //void*不能直接取变量 使用时候必须做类型转换 4 { 5 int i; 6 while(bytes-->0) 7 printf("%02x ",*(unsigned char*) addr++); 8 printf("\n"); 9 } 10 11 int main(){ 12 int n=1234567890; 13 float f=1234567890; 14 double d =1234567890; 15 short s=1234567890; 16 17 // printf("%x,%hs\n",n,s); 18 showbyte(&n,sizeof(n)); 19 showbyte(&f,sizeof(f)); 20 showbyte(&d,sizeof(d)); 21 showbyte(&s,sizeof(s)); 22 return 0; 23 }
Assignment:
1. 指针基本用来处理字符串
2. 写一个函数用来统计一个字符串中是否是数字字符串。
isdigitstr("123"):1, isdigitstr("asfw“):0, isdigitstr("12f"):0
3. 写一个函数用来统计一个字符串中是否是实数字符串。
isreal("12.3"):1,isreal("-45"):1,isreal("ase"):0,isreal("1.ew")
4. 写一个函数用来把一个字符串用制定的字符作为分隔符 分割成若干个字符子串 并且输出
substr("abc:de:fghi:jk",‘:‘) 输出
abc de fghi jk
5. 一个函数用来返回一个字符串中重复出现的最长子串的长度以及开始位置。
const char* P = NULL;
int len=maxsubstr("qweohiuweyowohifpw",&p)
len3, p是"ohi"的地址
printf("len=%d,substr=%s\n",len,p)
输出len=3,substr=ohifpw