目录
一、&数组名VS数组名
二、数组指针
三、指针数组
四、函数指针
五、const和指针
1、常量指针
六、sizeof和指针、数组
七、strlen和字符数组
八、指针和数组笔试题
1、一维数组
2、字符数组
3、二维数组
一、&数组名VS数组名
//试试这段代码
#include <stdio.h>int main(){int arr[10] = { 0 };printf("arr = %p\n", arr);printf("&arr= %p\n", &arr);}printf("arr+1 = %p\n", arr+1);printf("&arr+1= %p\n", &arr+1);return 0;
根据上面的代码我们发现,其实&arr和arr,虽然值是一样的,但是意义应该不一样的。
数组名表示数组首元素的地址,&数组名 表示的是数组的地址,而不是数组首元素的地址。
本例中&arr 的类型是: int(*)[10] ,是一种数组指针类型 数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40。
1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
2. &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。 除此1,2两种情况之外,所有的数组名都表示数组首元素的地址。
注意:数组名表示首元素的地址,二维数组的首元素是二维数组的第一行。
二、数组指针
数组指针是指向数组的指针。
int * p1[10];
int (*p2)[10];
//p1, p2分别是什么?
p1与[]结合,是指针数组,数组存放int类型的指针
p2与*结合,是数组指针,指针指向一个大小为10个整型的数组
这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。
三、指针数组
指针数组是存放指针的数组。
int* arr1[10]; //整形指针的数组
char * arr2[4]; //一级字符指针的数组
char ** arr3[5];//二级字符指针的数组
数组指针和指针数组
int arr[5]; //数组
int *parr1[10]; //指针数组
int (*parr2)[10]; //数组指针
int (*parr3[10])[5]; //与[]结合所以是数组,数组有10个元素,数组元素的类型是int(*)[5]数组指针类型
四、函数指针
//看一段代码
#include <stdio.h>void test(){printf("hehe\n");}int main(){printf("%p\n", test);printf("%p\n", &test);return 0;}
输出的是两个地址,这两个地址是 test 函数的地址。
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void *pfun2();
存储地址,就要求pfun1或者pfun2是指针。 pfun1可以存放,pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无参数,返回值类型为void。
五、const和指针
关键字const
用来定义常量,如果一个变量被const
修饰,那么它的值就不能再被改变。
1、常量指针
常量指针是指 针指向的内容是常量,可以有以下两种定义方式。
const int * p;
int const * p;
- const在*左边,修饰的是*p,即p指向的值 ,所以不能通过这个指针改变变量的值。
- 常量指针指向的值不能改变,但是这并不意味着指针本身不能改变,常量指针可以指向其他的地址。
2、指针常量
指针常量是指 指针本身是个常量,不能再指向其他的地址,写法如下:
int *const p;
- const在*右边,修饰的是p,所以p这个指针的指向不能变。
- 指针常量指向的地址不能改变,但是地址中保存的数值是可以改变的。
六、sizeof和指针、数组
sizeof的作用是用来返回()里面的变量或者数据类型占用的内存字节数。
sizeof(数组名) 计算的是数组占用的存储大小;
sizeof(指针)在64位系统下是8字节,在32位系统下是4字节。
七、strlen和字符数组
size_t strlen ( const char * str );
1、字符串已经'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前面出现的字符个数(不包 含'\0')。
2、参数指向的字符串必须要以 '\0' 结束。
八、指针和数组笔试题
1、一维数组
//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));
64位下运行结果:
sizeof(a):sizeof数组名指整个数组的大小,所以是16个字节;
sizeof(a+0):a+0是首元素的地址,是指针类型,指针在64位下是8个字节;
sizeof(*a):*a是首元素,首元素的类型是int,所以是4个字节;
sizeof(a+1):a+1是第二个元素的地址,是指针类型,指针在64位下是8个字节;
sizeof(a[1]):a[1]是第二个元素,是int类型,4个字节;
sizeof(&a):&a表示数组的地址,是指针类型,指针在64位下是8个字节;
sizeof(*&a):*&a表示整个数组,大小是16字节;
sizeof(&a+1):&a+1依然是一个指针,在64位下是8个字节;
sizeof(&a[0]):&a[0]是首元素的地址,指针类型,在64位下是8个字节;
sizeof(&a[0]+1):&a[0]+1是第二个元素的地址,是指针类型,指针在64位下是8个字节。
2、字符数组
//字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+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));
64位:
注释掉的是因为编译报错。
strlen接收的是char*类型的参数。
因为数组里面没存\0,但strlen只有遇到\0才会结束,所以这只是个随机值。
char arr[] = "abcdef";printf("%d\n", sizeof(arr));printf("%d\n", sizeof(arr+0));printf("%d\n", sizeof(*arr));printf("%d\n", sizeof(arr[1]));printf("%d\n", sizeof(&arr));printf("%d\n", sizeof(&arr+1));printf("%d\n", sizeof(&arr[0]+1));printf("%d\n", strlen(arr));printf("%d\n", strlen(arr+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));
"abcdef"中隐藏一个\0,sizeof回把\0算进去,strlen只计算\0之前的个数,遇到\0才结束。
char *p = "abcdef";printf("%d\n", sizeof(p));printf("%d\n", sizeof(p+1));printf("%d\n", sizeof(*p));printf("%d\n", sizeof(p[0]));printf("%d\n", sizeof(&p));printf("%d\n", sizeof(&p+1));printf("%d\n", sizeof(&p[0]+1));printf("%d\n", strlen(p));printf("%d\n", strlen(p+1));printf("%d\n", strlen(*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));
3、二维数组
//二维数组int a[3][4] = {0};printf("%d\n",sizeof(a));printf("%d\n",sizeof(a[0][0]));printf("%d\n",sizeof(a[0]));printf("%d\n",sizeof(a[0]+1));printf("%d\n",sizeof(*(a[0]+1)));printf("%d\n",sizeof(a+1));printf("%d\n",sizeof(*(a+1)));printf("%d\n",sizeof(&a[0]+1));printf("%d\n",sizeof(*(&a[0]+1)));printf("%d\n",sizeof(*a));printf("%d\n",sizeof(a[3]));
九、指针笔试题
笔试题1
int main(){int a[5] = { 1, 2, 3, 4, 5 };int *ptr = (int *)(&a + 1);printf( "%d,%d", *(a + 1), *(ptr - 1));return 0;}//程序的结果是什么?
a+1指向第二个元素,ptr指向5的下一个位置,ptr是int*类型,所以ptr-1指向5。
笔试题2
struct Test{int Num;char *pcName;short sDate;char cha[2];short sBa[4];}*p;//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main(){printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;}
32位:
第一个相当于是结构体指针+1跳过了一个结构体的大小,20个字节;
第二个就是无符号长整形,跳过一个字节;
第三个是指针,跳过4个字节。
笔试题3
int main(){int a[4] = { 1, 2, 3, 4 };int *ptr1 = (int *)(&a + 1);int *ptr2 = (int *)((int)a + 1);printf( "%x,%x", ptr1[-1], *ptr2);return 0;}
ptr2:
因为是小端,所以是02 00 00 00
笔试题4
#include <stdio.h>int main(){int a[3][2] = { (0, 1), (2, 3), (4, 5) };int *p;p = a[0];printf( "%d", p[0]);return 0;}
考察逗号运算符:最后一个逗号后面表达式的值作为整个表达式的值。
所以int a[3][2] = { (0, 1), (2, 3), (4, 5) };-->int a[3][2] = {1,3,5}
二维数组:
1 3
5 0
0 0
所以输出结果是1
笔试题5
int main(){int a[5][5];int(*p)[5];p = a;printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;}
笔试题6
int main(){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));return 0;}
笔试题7
#include <stdio.h>int main(){char *a[] = {"work","at","alibaba"};char**pa = a;pa++;printf("%s\n", *pa);return 0;}
笔试题8
int main(){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);return 0;}