一. 指针数组
指针数组:数组里面存放的都是指针变量。
本质,是一个数组。 数组中数据元素是 指针。指针是字符类型指针,用的多。
cpp
数据类型 *数组名[整型常量]
cpp
char* a[4]={NULL};//初始化方法
char * b[5]={"hello","ok","how","are","you"}; // 指针指向了字符串常量去,只可以读取,不
可以修改
char str[8][100]={"hello","ok","how","are","you"};
char *str3[5]={str[0],str[1],str[3]};// 指针指向了数组,可以读取,可以修改
存放字符串使用字符数组,操作字符串使用指针。
存放多个字符串使用二维字符数组(多个字符串的话)。操作字符串数组使用 指针数组
cpp
//冒泡排序
void bubble_sort(char **ppstr, int size)
{
int i = 0, j = 0;
for(i = 1; i < size; i++)
{
for(j = 0; j < size - i; j++)
{
if(strcmp(ppstr[j],ppstr[j+1]) > 0)
{
//只是交换指针内部存储的地址
char *temp = ppstr[j];
ppstr[j] = ppstr[j+1];
ppstr[j+1] = temp;
}
}
}
}
//打印
void print(char **pptr,int size)
{
int i = 0;
for(i = 0;i < size; i++)
{
printf("%d %s\n",i,*(pptr + i));
}
}
//分割字符串
int main()
{
char str[100] = "how are you";
char *pstr[3] = {NULL};
int size = sizeof(pstr) / sizeof(pstr[0]);
char *temp = str;
pstr[0] = str;
int i = 1;
while(*temp)
{
if(*temp == ' ')
{
*temp = '\0';
pstr[i++] = temp+1;
}
temp++;
}
print(pstr, size);
bubble_sort(pstr, size);//对其进行冒泡排序
print(pstr, size);
return 0;
}
结果:

二. 数组指针
数组指针:对一个一维数组进行&操作,地址值不变,类型升级为指向整个数组的指针。
对数组指针执行解引用操作 (*) , 地址值不变, 类型降为指向第一个元素的指针。
应用:需要同二维数组配合使用。
把二维数组作为参数传参的时候,在被调函数中参数的数据类型会使用到。
数组名:数组名在大多数情况下都表示数组首元素的地址。下面两种情况例外:
1、sizeof(数组名):这里数组名表示整个数组的大小,计算的是整个数组的大小。
2、&数组名:表示取出整个数组的地址,加1跳过整个数组的大小。
注:情况一必须是数组名单独放在sizeof里面才可以:
cpp
int a[5] = { 0 };
printf("sizeof(a) is %lu\n",sizeof(a));
printf("sizeof(a + 1) is %lu\n",sizeof(a + 1));//这里a表示的是
//首元素的地址
结果:

cpp
int a[5] = {1,2,3,4,5};
printf("a addr is %p\n",a);
printf("a[0] addr is %p\n",&a[0]);
printf("a[1] addr is %p\n",&a[1]);
printf("*(a+1) is %d\n",*(a+1));
printf("a[1] is %d\n",a[1]);
printf("&a is %p\n",&a);
printf("&a+1 is %p\n",&a+1);
int (*pa)[5] = &a;//数组指针
三. 二级指针
二级指针:指向指针的指针。 在定义指针变量的时候,会开辟8个自己的空间 。指针变量本身也是有内存地址的。
对一级指针取地址操作,就会获得二级指针。
需要解引用两次 ,可以访问到数数据。
应用:
1). 如果在被调函数中,需要修改指针的指向(指针本身)。,就需要传递二级指针。
2) 如果在被调函数中,需要修改指针指向的内容(指针指向的变量数据)。,就需要传递一级指针
cpp
int main()
{
int a = 10;
int *pa = &a;
printf("a addr is %p\n",&a);
printf("pa is %p\n",pa);
printf("pa addr is %p\n",&pa);
int **ppa = &pa;//二级指针
printf("ppa is %p\n",ppa);
printf("**ppa is %d\n",**ppa);
return 0;
}
四. 有关指针的练习题
cpp
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
结果:2,5
cpp
struct Test//这个结构体大小为20字节
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p//假设p是0x100000
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
结果:0x100014 0x100001 0x100004
cpp
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 2000000(大多计算机是小端存储)
cpp
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
结果:1
cpp
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
结果: &p[4][2] - &a[4][2] 得到的是指针之间的元素个数(同一数组中,指针-指针得到的是指针之
间的元素个数) 可知结果是-4,本题的关键点在打印的格式,以%d的格式打印出-4,若以
%p的格式打印在打印出FFFFFFFC,因为地址没有原反补的概念,故直接打印出内存中的
值。
FFFFFFFC -4
cpp
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
结果:10 5 (指针的类型决定了加减操作跳过的字节数)
cpp
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
结果:at
cpp
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
结果:POINT ER ST EW
cpp
//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));//16
printf("%d\n",sizeof(a+0));//一个地址4或者8
printf("%d\n",sizeof(*a));//4
printf("%d\n",sizeof(a+1));//一个地址4或者8
printf("%d\n",sizeof(a[1]));//4
printf("%d\n",sizeof(&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
cpp
//二维数组
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]表示第0行,类型:int [4]
printf("%d\n",sizeof(a[0]+1));//一个地址4或者8
printf("%d\n",sizeof(*(a[0]+1)));//4
printf("%d\n",sizeof(a+1));//一个地址4或者8
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
printf("%d\n",sizeof(a[3]));//16
cpp
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
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));//这里*p会是一个野指针,段错误
printf("%d\n", strlen(p[0]));//同上
printf("%d\n", strlen(&p));//随机值
printf("%d\n", strlen(&p+1));//随机值
printf("%d\n", strlen(&p[0]+1));//5
cpp
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));//野指针,段错误
printf("%d\n", strlen(arr[1]));//野指针,段错误
printf("%d\n", strlen(&arr));//随机值
printf("%d\n", strlen(&arr+1));//随机值
printf("%d\n", strlen(&arr[0]+1));//5
cpp
//字符数组
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));//随机值,无结束标志\0
printf("%d\n", strlen(arr+0));//随机值,无结束标志\0
printf("%d\n", strlen(*arr));//野指针,段错误
printf("%d\n", strlen(arr[1]));//同上
printf("%d\n", strlen(&arr));//随机值
printf("%d\n", strlen(&arr+1));//随机值
printf("%d\n", strlen(&arr[0]+1));//随机值