目录
一、一维数组
二、字符数组
1、字符数组(题型一)
2、字符数组(题型二)
3、字符数组(题型三)
三、二维数组
四、指针笔试题
1、试题一
2、试题二
3、试题三
4、试题四
5、试题五
6、试题六
7、试题七
8、试题八
一维数组
int main()
{
int arr[] = { 1,2,3,4 };
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[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(*&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]));
printf("%d\n", sizeof(&arr[0]+1));
return 0;
}
答案解析
int main()
{
int arr[] = { 1,2,3,4 };
printf("%d\n", sizeof(arr)); // 16
//arr作为数组名单独放在sizeof()内部,计算的是整个数组大小,单位为字节
printf("%d\n", sizeof(arr+0)); // 4/8
//arr不是单独放在sizeof()内部,也无&,所以arr表示数组首元素地址,即arr+0也是首元素地址,地址大小在32平台下为4个字节,64平台下为8个字节
printf("%d\n", sizeof(*arr)); // 4
//arr是首元素地址,*arr就是数组首元素的大小
printf("%d\n", sizeof(arr+1)); // 4/8
//arr是首元素的地址,arr+1是数组第二个元素的地址,计算指针的大小,在32平台下为4个字节,64平台下为8个字节
printf("%d\n", sizeof(arr[1])); // 4
//arr[1]就是数组第二个元素的大小
printf("%d\n", sizeof(&arr)); // 4/8
//&arr表示取出数组的地址,也是地址,地址在32平台下为4个字节,64平台下为8个字节
printf("%d\n", sizeof(*&arr)); // 16
//&arr表示取出数组的地址,*&arr是访问整个数组的大小
printf("%d\n", sizeof(&arr+1)); // 4/8
//&arr取出数组的地址,&arr+1表示跳过整个数组,也是地址,大小为4/8
printf("%d\n", sizeof(&arr[0])); // 4/8
//arr[0]表示第一个元素地址,&arr[0]是第一个元素的地址,也是地址,大小为4/8
printf("%d\n", sizeof(&arr[0]+1)); // 4/8
//&arr[0]是第一个元素的地址,&arr[0]+1就是第二个元素的地址,大小为4/8
return 0;
}
关于sizeof()的两个例外:
1、sizeof(数组名) : 数组名表示整个数组,计算的是整个数组的大小,单位是字节。
2、&数组名: 数组名也表示整个数组,取出的是整个数组的地址。
除了这个2个例外,见到的所有的数组名都表示首元素的地址。
int main()
{
char arr[] = { 'a','b','c','b' };
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));
return 0;
}
答案解析
int main()
{
char arr[] = { 'a','b','c','b' };
printf("%d\n", sizeof(arr)); // 4
//arr是数组名,单独放在sizeof()内部,计算的是整个数组大小
printf("%d\n", sizeof(arr+0)); // 4/8
//arr不是单独放在sizeof()内部,也无&,计算首元素地址大小
printf("%d\n", sizeof(*arr)); // 1
//arr是首元素地址,*arr就是首元素
printf("%d\n", sizeof(arr[1])); // 1
//arr[1]表示数组第二个元素,计算数组第二个元素的大小
printf("%d\n", sizeof(&arr)); // 4/8
//&arr表示取出数组地址,也是地址,大小为4/8
printf("%d\n", sizeof(&arr+1)); // 4/8
//&arr取出数组地址,&arr+1跳过整个数组,也是地址,大小为4/8
printf("%d\n", sizeof(&arr[0]+1)); // 4/8
//&arr[0]是字符'a'的地址,加1是字符'b'的地址,大小为4/8
printf("%d\n", strlen(arr)); // 随机值
//arr是数组名,但是没有放在sizeof内部,也无&,arr就是首元素的地址
//strlen()得到arr后,从数组首元素的位置开始计算字符串的长度,直到找到\0
//但是arr内存的后边是否有\0,在什么位置是不确定的,所以\0之前出现了多少个字符是随机的。
printf("%d\n", strlen(arr + 0)); // 随机值
//arr是首元素地址,arr+0还是首元素地址
printf("%d\n", strlen(*arr)); // err
//arr是首元素地址,*arr是首元素,strlen就会把‘a’的ASCII码值 97 当成了地址,就会非法访问内存
printf("%d\n", strlen(arr[1])); // err
//arr[1]表示数组第二个元素,即字符'b'
printf("%d\n", strlen(&arr)); // 随机值
//&arr取出数组地址,数组地址也是指向起始位置
printf("%d\n", strlen(&arr + 1)); // 随机值
//&arr取出数组地址,&arr+1跳过整个数组
//arr内存的后边是否有\0,在什么位置是不确定的,所以\0之前出现了多少个字符是随机的。
printf("%d\n", strlen(&arr[0] + 1)); // 随机值
//&arr[0]是字符'a'的地址,加1是字符'b'的地址
//arr内存的后边是否有\0,在什么位置是不确定的,所以\0之前出现了多少个字符是随机的。
return 0;
}
int main()
{
char arr[] = "abcd";
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));
return 0;
}
答案解析
int main()
{
char arr[] = "abcd";
printf("%d\n", sizeof(arr)); // 5
//字符串末尾有一个结束标志'\0',所以arr数组有5个元素
printf("%d\n", sizeof(arr+0)); // 4/8
//arr不是单独放在sizeof()中,是首元素地址,arr+0也是首元素地址
printf("%d\n", sizeof(*arr)); // 1
//arr是首元素地址,*arr是第一个字符'a',sizeof(*arr)是字符'a'的大小,单位为字节
printf("%d\n", sizeof(arr[1])); // 1
//arr[1]是数组第二个字符'b'
printf("%d\n", sizeof(&arr)); // 4/8
//&arr取出数组地址
printf("%d\n", sizeof(&arr+1)); // 4/8
//&arr取出数组地址,&arr+1也是地址
printf("%d\n", sizeof(&arr[0]+1)); // 4/8
//&arr[0]取出首元素地址,&arr[0]+1也是地址
printf("%d\n", strlen(arr)); // 4
//strlen()遇到字符串末尾的结束标志'\0'停止,'\0'前有4个元素
printf("%d\n", strlen(arr+0)); // 4
//arr+0表示首元素地址
printf("%d\n", strlen(*arr)); // err
//arr表示首元素地址,*arr是首元素,strlen就会把'a'的ASCII码值97当成了地址
printf("%d\n", strlen(arr[1])); // err
//arr[1]是数组第二个元素
printf("%d\n", strlen(&arr)); // 6
//&arr取出数组地址,指向起始位置
printf("%d\n", strlen(&arr + 1)); // 随机值
//&arr取出数组地址,加1则跳过整个数组
printf("%d\n", strlen(&arr[0] + 1)); // 5
//&arr[0]取出首元素地址,加1是第二个元素地址
return 0;
}
int main()
{
char *arr = "abcd";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+1));
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[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 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[0] + 1));
return 0;
}
答案解析
int main()
{
char* p = "abcd";
printf("%d\n", sizeof(p)); // 4/8
//p是指针变量,存放的是数组首元素地址,大小为4/8
printf("%d\n", sizeof(p+1)); // 4/8
//p存放的是地址,p+1也是地址,大小为4/8
printf("%d\n", sizeof(*p)); // 1
//p存放的是首元素地址,*p是首元素,大小为1,单位为字节
printf("%d\n", sizeof(p[0])); // 1
//p[0]是首元素,p[0] == *(p+0) == *p
printf("%d\n", sizeof(&p)); // 4/8
//p存放的是地址,&p取出p的地址,也是地址
printf("%d\n", sizeof(&p+1)); // 4/8
//&p+1是地址
printf("%d\n", sizeof(&p[0]+1)); // 4/8
//&p[0]+1是地址
printf("%d\n", strlen(p)); // 4
//p是指针变量,指向首元素地址
printf("%d\n", strlen(p + 1)); // 3
//p指向首元素地址,p+1指向第二个元素地址
printf("%d\n", strlen(*p)); // err
//*p是首元素
printf("%d\n", strlen(p[0])); // err
//p[0]是首元素
printf("%d\n", strlen(&p)); // 随机值
//&p取出的是p的地址,无法确定p的元素
printf("%d\n", strlen(&p + 1)); // 随机值
//&p取出的是p的地址,加1跳过p
printf("%d\n", strlen(&p[0] + 1)); // 5
//&p[0]是首元素地址,加1是第二个元素地址
return 0;
}
1、sizeof
sizeof 是计算对象或者类型创建的对象所占内存空间的大小,单位是字节。
sizeof 是操作符,不是函数。
2、strlen
strlen 求字符串长度的,计算的是字符串中\0之前出现的字符的个数。
统计到\0为止,如果没有看到\0,会继续往后找。
strlen 是库函数。
二维数组
int main()
{
int arr[3][4] = { 0 };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr[0][0]));
printf("%d\n", sizeof(arr[0]));
printf("%d\n", sizeof(arr[0] + 1));
printf("%d\n", sizeof(*(arr[0] + 1)));
printf("%d\n", sizeof(arr + 1));
printf("%d\n", sizeof(*(arr + 1)));
printf("%d\n", sizeof(&arr[0] + 1));
printf("%d\n", sizeof(*(&arr[0] + 1)));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[3]));
return 0;
}
答案解析
int main()
{
int arr[3][4] = { 0 };
printf("%d\n", sizeof(arr)); // 48
//arr是二维数组的数组名,数组名是单独放在sizeof内部,计算的是数组的总大小,单位是字节
printf("%d\n", sizeof(arr[0][0])); // 4
//a[0][0]是一个整型元素,大小是4个字节
printf("%d\n", sizeof(arr[0])); // 16
//arr[0]是第一行的数组名,第一行数组名单独放在sizeof内部,计算的是第一行数组的大小
printf("%d\n", sizeof(arr[0] + 1)); // 4/8
//arr[0]是第一行的数组名,但不是单独放在sizeof内部,所以是第一行首元素的地址
//加1是第一行第二个元素地址,就arr[0][1]的地址,大小为4/8
printf("%d\n", sizeof(*(arr[0] + 1))); // 4
//arr[0]是第一行首元素地址,加1是第一行第二个元素的地址,*(arr[0] + 1)是第一行第二个元素
printf("%d\n", sizeof(arr + 1)); // 4/8
//arr是二维数组的数组名,不是单独放在sizeof内部,也没有&,所以arr是首元素地址
//二维数组,我们把它想象成一维数组,它的首元素就是二维数组的第一行
//arr就是第一个的地址,加1是第二行地址,也是地址
printf("%d\n", sizeof(*(arr + 1))); // 16
//arr+1是第二行地址,sizeof(*(arr + 1))计算的就是第二行的大小
//*(arr + 1) == a[1]
printf("%d\n", sizeof(&arr[0] + 1)); // 4/8
//&a[0]是第一行的地址,&a[0]+1就是第二行的地址
printf("%d\n", sizeof(*(&arr[0] + 1))); // 16
&a[0]+1就是第二行的地址,sizeof(*(&arr[0] + 1))计算的是第二行的大小
printf("%d\n", sizeof(*arr)); // 16
//arr是首元素地址,是第一行的地址,sizeof(*arr)计算的是第一行的大小
printf("%d\n", sizeof(arr[3])); // 16
//arr[3]是二维数组的第四行
//虽然没有第四行,但是类型能够确定,大小就是确定的。大小就是一行的大小,单位是字节
return 0;
}
#include
int main()
{
int arr[5] = { 1,2,3,4,5 };
int* ptr = (int*)(&arr + 1);
printf("%d %d\n", *(arr + 1), *(ptr - 1));
return 0;
}
运行结果
解析
arr是数组首元素的地址,+1得到第二位元素的地址,对地址进行解引用得到第二位元素 2
&arr取出数组的地址,加1跳过整个数组
对跳过整个数组的地址-1,得到数组最后一位元素的地址,解引用得到 5
#include
//已知,结构体Test类型的变量大小是20个字节
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
int main()
{
p = (struct Test*)0x100000;
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
运行结果
解析
1、已知结构体的变量大小是20个字节,p是结构体指针类型,所以+1就是跳过20个字节,十进制的20等价于十六进制的14,所以 0x100000 + 0x00000014 = 0x00100014
2、这里将其强制类型转换成unsigned long,整数+1就是+1,所以 0x100000 + 0x00000001 = 0x00100001
3、这里将其强制类型转换为unsigned int*,+1就向后跳过4个字节,所以 0x100000 + 0x00000004 = 0x00100004;
#include
int main()
{
int a[4] = { 1, 2, 3, 4 };
int* ptr1 = (int*)(&a + 1);
int* ptr2 = (int*)((int)a + 1);
printf("%x,%x\n", ptr1[-1], *ptr2);
return 0;
}
运行结果
解析
1、&a是数组地址,+1跳过整个数组,ptr1[-1] == *(ptr-1),输出结果为4
2、将a强制类型转换为int 类型,再+1,在强制类型转化为指针实际上是向右移动一个字节,
对ptr2进行解引用,以16进制输出结果为2000000。
#include
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf("%d\n", p[0]);
return 0;
}
运行结果
解析
数组的初始化内容有逗号表达式,实际上初始化内容为1,3,5
p[0] == *(p+0) == *(p[0]+0)
#include
int main()
{
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]);
return 0;
}
运行结果
解析
1、由于二维数组和一维数组一样,在空间中都是连续存储的,把a赋值给p,&p[4][2]取出的是二维数组第19个元素的地址,&a[4][2]取出的是二维数组第23个元素的地址,由小地址-大地址得 -4。
2、因为-4的补码为11111111 11111111 11111111 11111100,内存中以补码的形式存储,以%p的形式打印,输出结果为FFFFFFFC。
#include
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;
}
运行结果
解析
1、&aa取出数组地址,加1则跳过整个数组,*(ptr1-1)的输出结果为10
2、aa是数组名,是首元素地址,二维数组中首元素地址就是第一行地址,加1则跳过第一行,得到第二行地址,对其进行解引用,就得到第二行,相当于第二行数组名,即为第二行首元素地址,*(ptr-1)的输出结果为5。
#include
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
运行结果
解析
a[]是一个指针数组,其中a[0]存放的是'w'的地址,a[1]存放的是'a'的地址,a[2]存放的是'a'的地址
pa = a 中,a为首元素地址,即为a[0]的地址,pa是一个二级指针,指向a[0],pa++指向a[1]
*pa输出结果为at
#include
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;
}
运行结果
解析
1、由于++cpp指向cp[1],解引用找到cp[1]中的元素c+2,再解引用找到字符’P’的地址,以%s的形式打印得到’POINT’
2、++cpp指向cp[2],解引用找到cp[2]中的元素c+1,然后前置--使得c+1变为c,在解引用找到字符'E'的地址,加3找到字符'E'的地址,以%s的形式打印得到‘ER’。
3、由于*cpp[-2] + 3 == *(*(cpp-2)+3,其中cpp-2解引用指向cp[0]中的元素c+3,再解引用找到字符'F'的地址,加3找到字符'S'的地址,以%s的形式打印得到’ST‘。
4、cpp[-1][-1]+1 == *(*(cpp-1)-1)+1,其中cpp-1解引用指向cp[1]中的元素c+2,在减1,得到c+1,在解引用,得到字符'N'的地址,以%s的形式打印得到'EW'。