指针 与 数组
1 指针
指针变量也是一个变量 指针存放的内容是一个地址,该地址指向一块内存空间。
指针是一种数据类型。
2 指针变量的定义 指针类型(int * ) + 变量名 ( p ): 比如: int * p;这里就定义了一个int * 类型的变量:p;p是变量名,p所代表的内存空间里面存放着的是一个地址;回头看p的类型是什么:是“int * ”注意了,不是int,而是在int后面加了一个“*”;那么,p是一个int * 类型的指针变量。这里还有一个概念,就是间接访问:已经知道了p这个指针变量里面存放的是一个地址;那这个地址指向的另外一块空间,它里面的值是什么呢,它就是一个int类型的值。以“*”符号为中心点,向左边结合,表示指针类型:int *;向右边变量结合,表示间接访问:*p ; 看这一行代码:char *p = "i love you!"; “i love you!”编译器会把他们放在字符串常量区,那么,p的值就是这串英文的常量区地址。间接访问看下面的示例:
#include <stdio.h> int main() { char *p = "I Love You!"; while(*p!=0) { printf("%c \t",p[0]); p++; //地址+sizeof(char) } printf("\n"); return 0; }
运行:
I L o v e Y o u !
高亮部分 *p!=0 ,这里就是间接访问,字符串数组中,数组成员多少个,就有多少个*P;遍历能打印出所有成员。
数组 和 指针
看示例:
#include <stdio.h> int main() { int a[100]={1,2,3,4,5,6,7,8,9,10}; int *p; p = a; p[3] = 100; int i; for(i = 0; i < sizeof(a)/sizeof(a[0]); i++) { printf("a[%d] = %d\n",i,p[i]); } return 0; }
运行:
abc@ubuntu:~$ gcc -o pointer pointer.c
abc@ubuntu:~$ pointer
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 100
a[4] = 5
a[5] = 6
a[6] = 7
a[7] = 8
a[8] = 9
a[9] = 10
abc@ubuntu:~$
当一个指针变量指向一个数组时,C语言规定指针变量名可以当数组使用。
再来看它们之间的区别1:指针大小在同一系统下是不变的,32位系统是4BYTE,64位系统是8BYTE。
#include <stdio.h> int main() { int a[10] = {1,2,3,4,5,6,7,8,9,10}; int *p; p = a; p[3] = 100; printf("%lu,%lu\n",sizeof(a),sizeof(p)); int i; for(i = 0; i <sizeof(a)/sizeof(a[0]); i++) { printf("a[%d] = %d\n", i, p[i]); } return 0; }
数组的大小是40,指针的大小始终不变。
运行:
abc@ubuntu:~$ gcc -o pointer pointer.c
abc@ubuntu:~$ pointer
40,8
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 100
a[4] = 5
a[5] = 6
a[6] = 7
a[7] = 8
a[8] = 9
a[9] = 10
abc@ubuntu:~$
#include <stdio.h> int main() { int a[10] = {1,2,3,4,5,6,7,8,9,10}; int *p; p = a; p[3] = 100; a[4] = 500; printf("%lu,%lu\n",sizeof(a),sizeof(p)); int i; for(i = 0; i <sizeof(a)/sizeof(a[0]); i++) { printf("a[%d] = %d\n", i, a[i]); } return 0; }
运行:
abc@ubuntu:~$ gcc -o pointer pointer.c
abc@ubuntu:~$ pointer
40,8
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 100
a[4] = 500
a[5] = 6
a[6] = 7
a[7] = 8
a[8] = 9
a[9] = 10
abc@ubuntu:~$
修改为数组命名,结果一样。
再看:数组和指针的区别2
1 #include <stdio.h> 2 3 int main() 4 { 5 int a[10] = {1,2,3,4,5,6,7,8,9,10}; 6 int *p; 7 p = &a[5]; 8 p[3] = 100; 9 a[4] = 500; 10 printf("%lu,%lu\n",sizeof(a),sizeof(p)); 11 int i; 12 for(i = 0; i <sizeof(a)/sizeof(a[0]); i++) 13 { 14 printf("a[%d] = %d\n", i, a[i]); 15 } 16 return 0; 17 }
运行:
abc@ubuntu:~$ gcc -o pointer pointer.c
abc@ubuntu:~$ pointer
40,8
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 500
a[5] = 6
a[6] = 7
a[7] = 8
a[8] = 100
a[9] = 10
abc@ubuntu:~$
代码中把a[5]的地址给了指针变量,那么指针p就把a[5]的地址认为p[0],p[1],p[2],p[……]地址依次向后。所以修改p[3]的值,就会是a[8]的值。
指针的计算
#include <stdio.h> int main() { int a[10]= {0}; int *p = a; p += 5; *p = 1; p -= 2; *p = 3; int i ; for(i = 0; i<sizeof(a)/sizeof(a[0]); i++) { printf("%a[%d] = %d\n",i, a[i]); } return 0; }
运行:
abc@ubuntu:~$ gcc -o p_count p_count.c
abc@ubuntu:~$ p_count
a[0] = 0
a[1] = 0
a[2] = 0
a[3] = 3
a[4] = 0
a[5] = 1
a[6] = 0
a[7] = 0
a[8] = 0
a[9] = 0
abc@ubuntu:~$
看代码,首先int *p = a ; 这时p还和a下标对应,到了p+= 5;这时p[0]指向就向后面移动了5个空间,对应a[5]了。p -=2;就再把p[0]指向向前移动了2个空间,指向了a[3],最后*p=3;就是修改的p[0]对应的a[3]。
指针可以加,可以减,但不可以乘除。
#include <stdio.h> int main() { int a[] = {1,2,3,4,5,6,7,8,9,10}; int *p = a; //指针p指向a的首地址 //p[3] = 100; *(p+3) = 100; int i; for(i = 0; i< sizeof(a)/sizeof(a[0]); i++) { printf("a[%d] = %d\n",i, a[i]); } return 0; }
运行:
abc@ubuntu:~$ gcc -o count_p count_p.c
abc@ubuntu:~$ count_p
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 100
a[4] = 5
a[5] = 6
a[6] = 7
a[7] = 8
a[8] = 9
a[9] = 10
abc@ubuntu:~$
再看:
#include <stdio.h> int main() { unsigned int num = 987654321; unsigned char *p =(unsigned char *)# //p =(char *)# int i; for (i = 0; i<4; i++) { printf("num[%d] = %d\n",i, p[i]); } return 0; }
示范:输入一个Ip地址,转换成整数
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> bool IsBigEndian() { short int n = 0x1122;//十六进制,一个数值占4位 char c = *(char *)&n; //通过将short(2字节)强制类型转换成char单字节,c指向n的起始字节(低字节) if (c == 0x11)//低字节存的是数据的高字节数据 { //是大端模式 return true; } else { //是小端模式 return false; } } int main() { char a[255] = {0}; scanf("%s.%s.%s.%s", &a); unsigned int ip = 0; unsigned char * p = (unsigned char *)&ip; unsigned int a1, a2, a3, a4; sscanf(a,"%u.%u.%u.%u", &a1, &a2, &a3, &a4); //判断大小端 if (IsBigEndian()) { *p = a1; p++; *p = a2; p++; *p = a3; p++; *p = a4; } else { *p = a4; p++; *p = a3; p++; *p = a2; p++; *p = a1; } printf("%u", ip); return 0; }
运行:
#include <stdio.h> int main() { char a[2][5] = {{16,3,6,2,9},{56,32,8,1,98}}; char *p = (char *)a; int i, j; for (i = 0; i < sizeof(a); i++) { for (j = 1; j < sizeof(a)-i; j++) { if (p[j] < p[j - 1]) { char tmp = p[j-1]; p[j-1] = p[j]; p[j] = tmp; } } } for (i = 0; i < sizeof(a) / sizeof(a[0]); i++) { for (j = 0; j < sizeof(a[0]) / sizeof(a[0][0]); j++) { printf("%d\n", a[i][j]); } } return 0; }
把二维数组看成一维数组的char指针冒泡。运行:
指针数组
二级指针