指针使C语言威力无穷 利用指针,可以高效地表示复杂数据结构,改变作为参数传送给函数的值,处理已经被“动态”分配的内存,以及更简洁、高效地处理数组。
指针(基本介绍) 指针百度 指针,是C语言中的一个重要概念及其特点,也是掌握C语言比较困难的部分。指针也就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。
内存地址
变量
指向变量的指针
定义
int number
int *p
变量值
5
000000000062FE08
地址
000000000062FE08
000000000062FE0F
指针和间接性 指针为访问一个具体数据项的取值提供了一种间接方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> int main (void ) { int a; int *p=&a; printf ("please input an integer:" ); scanf ("%d" ,&a); printf ("a=%d\n" ,a); printf ("please input an integer again:" ); scanf ("%d" ,p); printf ("a=%d\n" ,a); return 0 ; }
定义指针变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> int main (void ) { char a = 'F' ; int f = 123 ; char *pa = &a; int *pb = &f; printf ("a = %c\n" ,*pa); printf ("f = %d\n" ,*pb); return 0 ; }
指针操作
指针p
操作
意义
取地址
p=&a
将数据a的首地址赋值给p
取内容
*p
取出指针指向的数据单元
加
p++
使指针向下移动1个数据宽度
加
p=p+5
使指针向下移动5个数据宽度
减
p–
使指针向上移动1个数据宽度
减
p=p-5
使指针向上移动5个数据宽度
利用指针运算,可以访问数据 和计算字符串长度
访问数据 1 2 3 4 5 6 7 8 9 10 #include <stdio.h> int main (void ) { int b[5 ]={1 ,2 ,3 ,4 ,5 }; printf ("*b=%d,*(b+1)=%d,*(b+2)=%d\n" ,*b,*(b+1 ),*(b+2 )); return 0 ; }
计算字符串长度 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> int main (void ) { char str[]="I love 0nedeer.com!" ; char *target=str; int count=0 ; while (*target++ != '\0' ) { count++; } printf ("总共有%d个字符!\n" ,count); return 0 ; }
指针与… 多层指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> int main (void ) { int num = 520 ; int *p = # int **pp = &p; printf ("num: %d\n" ,num); printf ("*p: %d\n" ,*p); printf ("**p: %d\n" ,**pp); printf ("&p: %d\n , pp: %d\n" ,&p,pp); printf ("&num: %d\n , p: %d , *pp: %d\n" ,&num,p,*pp); return 0 ; }
结构体 指向结构体的指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <stdio.h> int main (void ) { struct date { int month; int day; int year; }; struct date today , *datePtr ; datePtr=&today; datePtr->month=9 ; datePtr->day=13 ; datePtr->year=2023 ; printf ("today's date is %i/%i/%.2i.\n" , datePtr->month,datePtr->day,datePtr->year %100 ); return 0 ; }
包含指针的结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <stdio.h> int main (void ) { struct intPtrs { int *p1; int *p2; }; struct intPtrs pointers ; int i1 = 100 , i2; pointers.p1=&i1; pointers.p2=&i2; *pointers.p2=-97 ; printf ("i1=%i,*pointers.p1=%i\n" ,i1,*pointers.p1); printf ("i2=%i,*pointers.p2=%i\n" ,i2,*pointers.p2); return 0 ; }
链表 如果将指针赋值为某变量的地址,就是将指针指向某变量 指针的最大作用:构造数据结构 使用指针可将不连续的内存空间连接到一起 从而实现独立节点的创建、连接和遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdio.h> int main (void ) { struct entry { int value; struct entry *next ; }; struct entry n1 ,n2 ,n3 ; int i; n1.value=100 ; n2.value=200 ; n3.value=300 ; n1.next=&n2; n2.next=&n3; i=n1.next->value; printf ("%i " ,i); printf ("%i\n" ,n2.next->value); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <stdio.h> int main (void ) { struct entry { int value; struct entry *next ; }; struct entry n1 ,n2 ,n3 ; struct entry *list_pointer = &n1; n1.value=100 ; n1.next=&n2; n2.value=200 ; n2.next=&n3; n3.value=300 ; n3.next=(struct entry *)0 ; while (list_pointer != (struct entry *)0 ){ printf ("%i\n" ,list_pointer->value); list_pointer=list_pointer->next; } return 0 ; }
数组 数组指针 int *p1[5]
本质是指针,指向一个数组
当定义一个用于指向数组元素的指针时,不是将该指针规定为“指向数组”类型,而是规定为该指针指向的数组中所包含元素的类型。 如果有一个名为text的字符数组,可以用**char *textPtr;语句定义一个指针,用于指定text中的元素。 要将valuesPtr设定为指向values数组中的第一个元素,只需写出: valuesPtr=values;** ,在这种情况下不使用地址运算符,因为C编译器将不带下标的数组名看作指向该数组对的指针。(数组名其实是数组第一个元素的地址) valuesPtr = values; 等价于 valuesPtr = &values[0];
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> int main (void ) { int temp[5 ]={1 ,2 ,3 ,4 ,5 }; int (*p2)[5 ]=&temp; int i; for (i=0 ;i<5 ;i++) { printf ("%d\n" ,*(*p2+i)); } return 0 ; }
指针数组 int (*p1)[5]
本质是数组,包含许多个指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <stdio.h> int main (void ) { int a = 1 ; int b = 2 ; int c = 3 ; int d = 4 ; int e = 5 ; int *p1[5 ] = {&a,&b,&c,&d,&e}; int i; for (i=0 ;i<5 ;i++) { printf ("%d\n" ,*p1[i]); } return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <stdio.h> int main (void ) { char *p1[5 ]={ "let it go" , "just do it" , "dream it possible" , "never stop" , "one more thing" }; int i; for (i=0 ;i<5 ;i++) { printf ("%s\n" ,p1[i]); } return 0 ; }
二维数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> int main (void ) { int array [2 ][3 ]={{0 ,1 ,2 },{3 ,4 ,5 }}; int (*p)[3 ]=array ; printf ("**(p+1):%d\n" ,**(p+1 )); printf ("**(array+1):%d\n" ,**(array +1 )); printf ("array[1][0]:%d\n" ,array [1 ][0 ]); printf ("*(*(p+1)+2):%d\n" ,*(*(p+1 )+2 )); printf ("*(*(array+1)+2):%d\n" ,*(*(array +1 )+2 )); printf ("array[1][2]:%d\n" ,array [1 ][2 ]); return 0 ; }
*(array+i) == array[i]
*(*(array+i)+j) == array[i][j]
*(*(*(array+i)+j)+k) == array[i][j][k]
*(array+1) == &array[1][0] == array[1]
*(array+1)+3 == &array[1][3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <stdio.h> int main (void ) { int array [4 ][5 ]={0 }; int i,j,k=0 ; for (i=0 ;i<4 ;i++) { for (j=0 ;j<5 ;j++) { array [i][j]=k++; } } printf ("*(array+1):%p\n" ,*(array +1 )); printf ("array[1]:%p\n" ,array [1 ]); printf ("&array[1][0]:%p\n" ,&array [1 ][0 ]); printf ("**(array+1):%d\n" ,**(array +1 )); printf ("*(*(array+1)+3):%d\n" ,*(*(array +1 )+3 )); printf ("array[1][3]:%d\n" ,array [1 ][3 ]); return 0 ; }
常量(const修饰) const int *p
指针指向位置可修改,指针指向变量的内容只能随着变量改变而改变,不能通过解引用修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdio.h> int main (void ) { int num=520 ; int cnum=880 ; const int *pc=&cnum; printf ("cnum:%d, &cnum:%p\n" ,cnum,&cnum); printf ("*pc:%d, pc:%p\n" ,*pc,pc); cnum=7 ; printf ("cnum:%d, &cnum:%p\n" ,cnum,&cnum); printf ("*pc:%d, pc:%p\n" ,*pc,pc); pc=# printf ("num:%d, &num:%p\n" ,num,&num); printf ("*pc:%d, pc:%p\n" ,*pc,pc); num=1024 ; printf ("*pc:%d, pc:%p\n" ,*pc,pc); return 0 ; }
const int *p
指针指向位置不可修改,指针指向变量的内容可通过变量改变而改变,也可通过解引用修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h> int main (void ) { int num=520 ; int cnum=880 ; int * const p=# printf ("*p: %d, num: %d\n" ,*p,num); *p=1024 ; printf ("*p: %d, num: %d\n" ,*p,num); num=666 ; printf ("*p: %d, num: %d\n" ,*p,num); return 0 ; }
const int * const p
指针指向位置不可修改,指针指向变量的内容只能随着变量改变而改变,不能通过解引用修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h> int main (void ) { int num=520 ; const int * const p = # printf ("*p: %d, num: %d\n" ,*p,num); num = 1024 ; printf ("*p: %d, num: %d\n" ,*p,num); return 0 ; }
参数 指针可用于传递参数
传址大数据 传值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <stdio.h> void fun (int param) { param=0x88 ; printf ("%x\n" ,param); } int main (void ) { int a=0x66 ; fun(a); printf ("%x\n\n\n\n" ,a); return 0 ; }
传址 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <stdio.h> int FindMax (const int *array ,int Count) { int i; int max=array [0 ]; for (i=1 ;i<Count;i++) { if (array [i]>max) { max=array [i]; } } return max; } int main (void ) { int a[]={13 ,2 ,3 ,5 ,4 ,30 }; int Max; Max=FindMax(a,6 ); printf ("Max=%d\n" ,Max); return 0 ; }
传址破作用域 传值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <stdio.h> void swap (int x,int y) ;void swap (int x,int y) { int temp; printf ("In swap,互换前:x= %d , y= %d\n" ,x,y); temp=x; x=y; y=temp; printf ("In swap,互换后:x= %d , y= %d\n" ,x,y); } int main (void ) { int x=3 ,y=5 ; printf ("In main,互换前:x= %d , y= %d\n" ,x,y); swap(x,y); printf ("In main,互换后:x= %d , y= %d\n" ,x,y); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <stdio.h> void swap (int *x,int *y) ;void swap (int *x,int *y) { int temp; printf ("In swap,互换前:x= %d , y= %d\n" ,*x,*y); temp=*x; *x=*y; *y=temp; printf ("In swap,互换后:x= %d , y= %d\n" ,*x,*y); } int main (void ) { int x=3 ,y=5 ; printf ("In main,互换前:x= %d , y= %d\n" ,x,y); swap(&x,&y); printf ("In main,互换后:x= %d , y= %d\n" ,x,y); return 0 ; }
传数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <stdio.h> int FindMaxAndCount (int *max,int *count,const int *array ,int length) { int i; *max=array [0 ]; *count=1 ; for (i=1 ;i<length;i++) { if (array [i]>*max) { *max=array [i]; *count=1 ; } else if (array [i]==*max) { (*count)++; } } } int main (void ) { int a[]={30 ,2 ,30 ,5 ,4 ,30 }; int Max; int Count; FindMaxAndCount(&Max,&Count,a,6 ); printf ("Max=%d\n" ,Max); printf ("Count=%d\n" ,Count); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <stdio.h> int FindMaxAndCount (int *max,int *count,const int *array ,int length) { int i; *max=array [0 ]; *count=1 ; for (i=1 ;i<length;i++) { if (array [i]>*max) { *max=array [i]; *count=1 ; } else if (array [i]==*max) { (*count)++; } } } int main (void ) { int a[]={30 ,2 ,30 ,5 ,4 ,30 }; int Max; int Count; FindMaxAndCount(&Max,&Count,a,6 ); printf ("Max=%d\n" ,Max); printf ("Count=%d\n" ,Count); return 0 ; }
函数 指针函数 int *p()
本质是函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <stdio.h> char *getword (char ) ;char *getword (char c) { switch (c) { case ' A' :return "Apple" ; case 'B ' :return "Banana" ; case ' C' :return "Cat" ; case ' D' :return "Dog" ; default :return "None" ; } } int main (void ) { char input; printf ("请输入一个字母: " ); scanf ("%c" ,&input); printf ("%s\n" ,getword(input)); return 0 ; }
函数指针 int (*p)()
本质是指针,指向函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <stdio.h> int square (int ) ;int square (int num) { return num * num; } int main (void ) { int num; int (*fp)(int ); printf ("请输入一个整数: " ); scanf ("%d" ,&num); fp=square; printf ("%d * %d = %d\n" ,num,num,(*fp)(num)); return 0 ; }
函数指针作为参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <stdio.h> int add (int ,int ) ;int sub (int ,int ) ;int calc (int (*fp)(int ,int ),int ,int ) ;int add (int num1,int num2) { return num1+num2; } int sub (int num1,int num2) { return num1-num2; } int calc (int (*fp)(int ,int ),int num1,int num2) { return (*fp)(num1,num2); } int main (void ) { printf ("3+5=%d\n" ,calc(add,3 ,5 )); printf ("3-5=%d\n" ,calc(sub,3 ,5 )); return 0 ; }
函数指针作为返回值 函数指针作为返回值,可返回多个值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <stdio.h> int add (int ,int ) ;int sub (int ,int ) ;int calc (int (*fp)(int ,int ),int ,int ) ;int (*select(char op))(int ,int );int add (int num1,int num2) { return num1+num2; } int sub (int num1,int num2) { return num1-num2; } int calc (int (*fp)(int ,int ),int num1,int num2) { return (*fp)(num1,num2); } int (*select(char op))(int ,int ){ switch (op) { case ' +':return add; case' -':return sub; } } int main(void) { int num1,num2; char op; int (*fp)(int,int); printf("请输入一个式子(如1+3):"); scanf("%d%c%d",&num1,&op,&num2); fp=select(op); printf("%d%c%d=%d\n",num1,op,num2,calc(fp,num1,num2)); return 0; }
void指针和NULL指针 void指针 void即无类型 void指针(通用指针)可以指向任意类型的数据,支持各种类型指针的转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h> int main (void ) { int num = 1024 ; int *pi = # char *ps = "FishC" ; void *pv; pv=pi; printf ("pi:%p, pv:%p\n" ,pi,pv); printf ("*pv:%d\n" ,*(int *)pv); pv=ps; printf ("ps:%p, pv:%p\n" ,ps,pv); printf ("*pv:%s\n" ,(char *)pv); return 0 ; }
NULL指针 用于指针和对象,表示指向一个不被使用的地址
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> int main (void ) { int *p1; int *p2 = NULL ; printf ("%d\n" ,*p1); printf ("%d\n" ,*p2); return 0 ; }
指针应用
指针优势