这篇文章是关于数组与指针的练习题,可以加深我们对指针与数组结合的理解
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//16 sizeof表达式里面a,代表着整个数组,不在是首元素的地址,
printf("%d\n", sizeof(a + 0));// 4/8 由于a不是单独放在sizeof表达式里面,所以a+0代表首元素的地址
printf("%d\n", sizeof(*a));//4 *a等同于a[0] ,表示首元素,因此得出第一个元素的大小
printf("%d\n", sizeof(a + 1));// 4/8 由于a不是单独放在sizeof表达式里面,所以a+1代表2元素的地址
printf("%d\n", sizeof(a[0]));// 4 表示元素2的大小
printf("%d\n", sizeof(&a));//4/8 &a 这里的a代表整个数组,但取出的地址是首元素的地址
printf("%d\n", sizeof(*&a));//16 先取出整个数组的地址,然后对整个数组解引用,因此代表着整个数组
printf("%d\n", sizeof(&a + 1));// 4/8 &a代表整个数组,加1就跳过了整个数组但依然是地址
printf("%d\n", sizeof(&a[2]));// 4/8
printf("%d\n", sizeof(&a[0] + 1));//4/8 取出的是元素2的地址
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));// 6 arr表示整个数组
printf("%d\n", sizeof(arr + 0));// 4/8 代表着数组首元素的地址
printf("%d\n", sizeof(*arr));//1 *arr代表着数组首元素
printf("%d\n", sizeof(arr[1]));//1 代表着元素b的大小
printf("%d\n", sizeof(&arr));// 4/8 取出的是整个数组, 但地址是先从首元素开始的 printf ("%d\n", sizeof(&arr + 1));//4/8 arr代表着整个数组,但是加1后跨过整个数组,所以取出的是最后一个元素之后的地址
printf("%d\n", sizeof(&arr[0] + 1));//4/8 ,取出的是元素b的地址
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));// strlen遇到'/0'才会停止读,但是这里没有'/0',所以是个随机值
printf("%d\n", strlen(arr + 0));//依旧是随机值
printf("%d\n", strlen(*arr));//strlen接收的是地址,出现错误
printf("%d\n", strlen(arr[1]));//错误
printf("%d\n", strlen(&arr));//&arr取出的是整个数组,从首元素开始,但是没有'/0' 依旧是随机值
printf("%d\n", strlen(&arr + 1));//&arr+1 跳过整个数组,但依旧是随机值
printf("%d\n", strlen(&arr[0] + 1));//从元素b开始计数,但依旧是随机值
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//7 注意'f'后面有一个'/0'
printf("%d\n", sizeof(arr + 0));//4 计算的是arr[0]的大小
printf("%d\n", sizeof(*arr));//1 计算的是arr[0]的大小
printf("%d\n", sizeof(arr[1]));//1
printf("%d\n", sizeof(&arr));//&arr 取出的是整个数组 但它依然是地址,所以是4/8
printf("%d\n", sizeof(&arr + 1));//4/8 表达式表示跨过一整个数组
printf("%d\n", sizeof(&arr[0] + 1));//4/8 表示元素b的地址
char arr[] = "abcdef";
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));//6 &arr 取出的是整个数组,但是它依旧是从首元素开始的,
printf("%d\n", strlen(&arr + 1));//随机值 跨过真个数组,直到遇见/0
printf("%d\n", strlen(&arr[0] + 1));//5
char* p = "abcdef"; //p是个指针,指向的是首元素地址
printf("%d\n", sizeof(p));//4/8 p是个指针,指向的是首元素地址
printf("%d\n", sizeof(p + 1));//4/8 指向元素b的地址
printf("%d\n", sizeof(*p));//1 元素a的大小
printf("%d\n", sizeof(p[0]));//1 元素a的大小
printf("%d\n", sizeof(&p));//4/8
printf("%d\n", sizeof(&p + 1));// 4/8
printf("%d\n", sizeof(&p[0] + 1));// 4/8
char* p = "abcdef"; //p是个指针,指向的是首元素地址
printf("%d\n", strlen(p));//6,p指向首元素的地址,
printf("%d\n", strlen(p + 1));//5 p+1指向的是b的地址,往后开始计数,一直到/0
//printf("%d\n", strlen(*p));//错误
//printf("%d\n", strlen(p[0]));//错误
printf("%d\n", strlen(&p));//随机值 p是指针,不是数组名,&p,取出的是p本身的地址
printf("%d\n", strlen(&p + 1));//随机值 跨国一个数组直到遇见新的'/0'
printf("%d\n", strlen(&p[0] + 1));//5
int a[3][4] = { 23 };
printf("%d\n", sizeof(a));//48 二维数组的数组名表示数组首元素的地址,但是它单独放在sizeof里面,所以表示整个数组
printf("%d\n", sizeof(a[0][0]));//4
printf("%d\n", sizeof(a[0]));//16 a[0]表示第一行一维数组的数组名,但是sizeof的数组名表示整个数组
printf("%d\n", sizeof(a[0] + 1));//4/8 表示第1行的第二个元素的地址
printf("%d\n", sizeof(*(a[0] + 1)));//4 表示第1行第2个元素的大小
printf("%d\n", sizeof(a + 1));//4/8, 表示的是第二行首元素的地址,(a+1)表示第二行的数组名
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 是第一行所有元素的大小,a是数组名,
//不是单独放在sizeof里面,所以表示的是第一行一维数组的数组名
printf("%d\n", sizeof(a[3]));//16 sizeof是表达式,不会判断括号里的结果是否正确
笔试题
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}//输出2,5 (&a+1)跨过去整个数组,来到5后面的一个地址,再减去1,正好指向5的地址
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//由于还没学习结构体,这里告知结构体的大小是20个字节
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
printf("%p\n", p + 0x1);
//p是个struct Test* 型,大小为20字节,p+1相当于地址加上20,由于地址是由16进制表示,20的16进制0x000014,0x100000+0x000014=0x100014
printf("%p\n", (unsigned long)p + 0x1);
//此时p被强制转化为unsigned long 无符号长整型,可以直接加0x1 ,所以为000001
printf("%p\n", (unsigned int*)p + 0x1);
//此时p被强制转换为(int *),大小为4个字节,加1 ,相当于加4,0000004
return 0;
}
int a[4] = { 1, 2, 3, 4 };
int* ptr1 = (int*)(&a + 1);//(&a+1)本来是int(*)[4]类型,被强制转换成(int*),4后面那块未知的地址就赋值给了ptr1
//ptr[-1]相当于ptr-1,最终指向4
int* ptr2 = (int*)((int)a + 1);//假设a数组首元素地址为0x11223300,此时被强制转为int,那么地址可以直接加1变为0x11223301,指针相当于往前走了1个字节,又因为再次被强制换为(int*) 需要访问4个字节,ptr2往后找四个字节一直到02,最终指向00 00 00 02,由于是小端存储,输出时变为200 00 00
printf("%x,%x", ptr1[-1], *ptr2);
return 0;
#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 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;
}//由下面的简图可以看出两者相差4个元素也就是4个字节,两个地址相减得到的之间元素的个数,以字节为单位.所以第二个输出的为-4,%p是以16进制输出,所以-4的16进制 fffffffc
//补充:计算机中通常使用补码来表示负数。补码表示法将负数转换为其对应的补码形式,使得负数的加法、减法等运算可以与正数一起使用相同的规则进行计算,简化了计算机的逻辑设计和运算过程。因此,负数在计算机中常用补码表示
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* ptr1 = (int*)(&aa + 1);//&aa表示整个二维数组,+1会跨过整个二维数组
int* ptr2 = (int*)(*(aa + 1));//数组名aa表示第一行的整个一维数组,加1,相当于aa[1]
printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5
return 0;
char* a[] = { "work","at","alibaba" };//3个字符串,char* p1 ="work";char* p2 = "at";//指针数组的空间不是连续的,无法用二维数组表示,两者不一样的概念
char** pa = a;//pa存放着p1的地址
pa++;//指向了p2
printf("%s \n",*pa);
return 0;
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };//++ 的优先于*,*优先于+ ,-
char*** cpp = cp;
printf("%s\n", **++cpp);//cpp先自增变为cpp+1,再*(cpp+1)取出cp+1,再*(cp+1),取出c+2 ==c[2]
printf("%s\n", *-- * ++cpp + 3);//此时的cpp指向cp+1,前置++,变为cp+2,*(c+1),取出c+1,然后--,变为c,再*,取出ENTER的首元素地址E,加3,地址变为E的地址
printf("%s\n", *cpp[-2] + 3);//先取出cp+3的内容c+3
//(表示的是FIRST的整个地址)
printf("%s\n", cpp[-1][-1] + 1);
//*(*(cpp-1)-1)+1 首先cpp-1指向cp+2再*取出里面的内容
//c+1,c+1再-1变为c 再*表示第一个整个字符串元素 *c+1中*c的地址,加一就来到了N的位置