一维数组、二维数组、strlen、sizeof的区别总结+八个指针题

#include <string.h>
int main()
{
    //arr一般书数组首元素的地址
      //sizeof(数组名)计算的是数组的大小单位字节,计算的是对象所占内存的大小
      //&arr取出的是地址整个数组的地址4或8字节
    int a[] = { 1,2,3,4 };
    //报警高是因为是64位平台,改成llu就好
    printf("%llu\n", sizeof(a));//4*4=16整个数组的大小
    printf("%d\n", sizeof(a + 0));//a+0数组第一个元素的地址,是地址就是4或8个字节
    printf("%d\n", sizeof(*a));//4 a表示数组首元素的地址,*a表示数组第一个元素,大小就是4
    printf("%d\n", sizeof(a + 1));//4 / 8 a表示数组首元素的地址,a+1数组第二个元素的地址,sizeof(a+1)就是第二个元素的地址的大小
    printf("%d\n", sizeof(a[1]));//4 计算的是第二个元素的大小
    printf("%llu\n", sizeof(&a));//4 / 8 &a取出的是数组的地址,是地址,数组的地址就是4/8字节
    printf("%d\n", sizeof(*&a));//16 计算的是整个数组的大小,&和*,相反相当于a, 如果不在sizeof里面就是数组首元素地址
    printf("%d\n", sizeof(&a + 1));// 4/8 &a数组的地址,+1跳过整个数组
    printf("%d\n", sizeof(&a[0]));//4/8 是数组首元素的地址
    printf("%d\n", sizeof(&a[0] + 1));//4/8 数组第二个元素的地址




    //二维数组
#include <stdio.h>
    int main()
    {
        int a[3][4] = { 0 };
        printf("%d\n", sizeof(a));//48=4*3*4整个数组的大小
        printf("%d\n", sizeof(a[0][0]));//4-第一行第一个元素的大小
        printf("%d\n", sizeof(a[0]));//16 a[0]是第一行数组名,sizeof(a[0])就是第一行数组名单独放在sizeof内部,计算的是第一行的大小
        printf("%d\n", sizeof(a[0] + 1));//4/8  a[0]作为第一行数组名,并没有单独放在sizeof内部,也没有被取地址,所以a[0]就是数组首元素的地址,就是第一行第一个元素的地址,a[0]+1就是第一行第二个元素的地址
        printf("%d\n", sizeof(*(a[0] + 1)));//4 第二个元素的大小
        printf("%d\n", sizeof(a + 1));//4/8 a是首元素的地址,a是二维数组,首元素的地址就是第一行的地址,a+1就是第二行的地址
        printf("%d\n", sizeof(*(a + 1)));//16 对第二行的地址解引用访问就是第二行//*(a+1)->a[1]//sizeof(a[1]),不加sizeof解引用就是拿到数组名就是第二行数组首元素的地址
        printf("%d\n", sizeof(&a[0] + 1));//4/8 a[0]是第一行数组名,&a[0]取出的是第一行地址,&a[0]+1就是第二行的地址
        printf("%d\n", sizeof(*(&a[0] + 1)));//16  对第二行的地址解引用访问就是第二行
        printf("%d\n", sizeof(*a));//16  a就是数组首元素的地址,就是第一行的地址,*a就是第一行//*a->*(a+0)->a[0]
        printf("%d\n", sizeof(a[3]));//16 int[4] 不会访问内存,知道是int类型,四个元素
        return 0;
    }




    char arr[] = { 'a','b','c','d','e','f' };//已初始化,没有\0 
    报警高是因为是64位平台,改成llu就好
    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  数组第二个元素的地址



    //char arr[] = { 'a','b','c','d','e','f' };
    //就是找\0才停止
    printf("%d\n", strlen(arr));//随机值,arr数组中没有\0,会继续找\0找到为止
    printf("%d\n", strlen(arr + 0));//随机值,arr+0是数组首元素地址
    //printf("%d\n", strlen(*arr));//err-arr是数组首元素的地址,*arr是数组首元素,就是'a'-97,把97当成地址了,不对。
    //printf("%d\n", strlen(arr[1]));//err, 'b'-98
    printf("%d\n", strlen(&arr));//随机值  整个数组的地址,开始都在首元素哪里,和arr差不多
    printf("%d\n", strlen(&arr + 1));//随机值,数组后面那个地址开始数
    printf("%d\n", strlen(&arr[0] + 1));//随机值,从'b'开始数

    return 0;
}


//sizeof是一个操作符
//sizeof计算的是对象所占内存的大小-单位是字节,不能模拟
//不在乎内存中放的是什么,只在乎内存大小

//strlen是库函数
//求字符串的长度,从给定的地址访问字符,统计\0之前出现的字符个数
#include <stdio.h>
#include <string.h>
int main()
{
    char arr[] = "abcdef";//a b c d e f \0
    报警高是因为是64位平台,改成llu就好
    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  \0后面的地址
    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));//err
    //printf("%d\n", strlen(arr[1]));//err
    printf("%d\n", strlen(&arr));//6
    printf("%d\n", strlen(&arr + 1));//随机值;从\0后面开始找\0
    printf("%d\n", strlen(&arr[0] + 1));//5;数组第二个元素的地址
    return 0;
}


#include <stdio.h>
#include <string.h>
int main()
{
    char* p = "abcdef";
    //假设a的地址0x00ff1140,b - 0x00ff1141
    //p的地址就是0x00ff1140
    printf("%d\n", sizeof(p));//4/8 p是指针变量,计算的是指针变量的大小
    printf("%d\n", sizeof(p + 1));//4/8,‘b'的地址
    printf("%d\n", sizeof(*p));//1,*p其实就是'a'
    printf("%d\n", sizeof(p[0]));//1,p[0]->*(p+0)->*p
    printf("%d\n", sizeof(&p));//4/8,是指针变量p在内存中的地址
    printf("%d\n", sizeof(&p + 1));//4/8, &p+1是跳过p之后的地址
    printf("%d\n", sizeof(&p[0] + 1));//4/8 &p[0]'a'的地址+1就是b的地址
    printf("%d\n", strlen(p));//6
    printf("%d\n", strlen(p + 1));//5,从b开始数
    printf("%d\n", strlen(*p));//err
    printf("%d\n", strlen(p[0]));//err
    printf("%d\n", strlen(&p));//随机值,p是指针变量,&p时指针变量的地址,不是地址的地址,和数组没关系
    printf("%d\n", strlen(&p + 1));//随机值
    printf("%d\n", strlen(&p[0] + 1));//5,从b开始数
    return 0;
}


//指针题1

#include <stdio.h>
int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int* ptr = (int*)(&a + 1);//&a+1地址在5的后面,然后把数组指针转化为整形指针形式一致
    //&a,数组的地址是数组指针类型
    printf("%d,%d", *(a + 1), *(ptr - 1));//2  5
    return 0;
}



//指针题2
//由于还没学习结构体,这里告知结构体的大小是20个字节
#include <stdio.h>
struct Test
{
    int Num;
    char* pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
    p = (struct Test*)0x100000;
    //加一个十六进制的结构体,类似arr+1
    printf("%p\n", p + 0x1);//p + 1*sizeof(结构体大小),00100014
    printf("%p\n", (unsigned long)p + 0x1);//强制类型转换为整形,加1就是1,00100001
    printf("%p\n", (unsigned int*)p + 0x1);//强制类型转换为int*(整形指针),加1就是4,00100004
    //00就是因为以%p打印的,就是以地址形式打印,,%x不会打印00,只打印有效位
    return 0;
}



//指针题3
#include <stdio.h>
int main()
{
    //假设是小端存储地址:低地址01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00高地址
    int a[4] = { 1, 2, 3, 4 };
    int* ptr1 = (int*)(&a + 1);//4后面的地址
    int* ptr2 = (int*)((int)a + 1);//a表示数组首元素的地址,假设地址是0x00000020(16进制=32)在01前面,
    //转换为整形,加1(32+1=33,),变成0x00000021,在01和00中间位置,
    //然后转换为int*类型,从00开始访问四个字节,00 00 00 02,小端存储,拿出来就是02 00 00 00
    printf("%x,%x\n", ptr1[-1], *ptr2);//ptr1[-1]->*(ptr1-1),地址解引用,-->4
    //*ptr2=02000000,如果按照%x,只保留有效位,*ptr2=2000000
    printf("%p,%p\n", ptr1[-1], *ptr2);//00000004, 02000000
    printf("%#x,%#x\n", ptr1[-1], *ptr2);//#->0x,0x4, 0x2000000
    return 0;
}



//指针题4
#include <stdio.h>
int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };//逗号表达式,所以数组最终初始化为1 3 5 0 0 0
    //int a[3][2] = { {0, 1}, {2, 3}, {4, 5} };才会初始化为0 1 2 3 4 5
    int* p;//定义p是指针
    p = a[0];//a[0]是通常型,是数组首元素的地址,1所在的地址,p存放的1的地址
    printf("%d", p[0]);//p[0]->*(p+0)->*p->*(a[0])=1
    return 0;
}



//指针题5具体画图在QQ里
#include <stdio.h>
int main()
{
    int a[5][5];
    int(*p)[4];
    p = a;
    //p[4][2]->*(*(p+4)+2)
    //指针-指针=两个地址中间元素的个数。算出是4个,但因为是低地址->高地址排列所以是-4
    printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
    //%d打印-4=-4
    //%p打印-4
    //10000000000000000000000000000100--原码
    //11111111111111111111111111111011--反码符号位不变其他位取反
    //11111111111111111111111111111100--补码-反码加1得到补码
    //打印地址直接打印FFFFFFFC
    return 0;
}



//指针题6
#include <stdio.h>
int main()
{
    int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int* ptr1 = (int*)(&aa + 1);//&aa数组的地址,+1,就是10后面的地址
    int* ptr2 = (int*)(*(aa + 1));// *(aa+1)->aa[1],解引用就是拿到第二行数组名,通用型,就是第二行数组首元素地址,6的地址,
    //假设不加*,只有aa+1,就是第二行地址,值一样,但意义不同
    printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//ptr1-1就是10所在的地址,解引用就是10
    //ptr2指向6的地址,ptr2-1指向5的地址,解引用就是5
    return 0;
}




//指针题7
#include <stdio.h>
int main()
{
    char* a[] = { "work","at","alibaba" };//work\0  at\0  alibaba\0  存放的char*只是每个元素的第一个字母w,a,a
    char** pa = a;//一级指针存放到二级指针里,pa指向a数组首元素地址,
    pa++;
    printf("%s\n", *pa);//at给一个地址,从地址开始往后打印字符串,到\0停,%s啊。%p打印的是地址
    return 0;
}


//指针题8
#include <stdio.h>
int main()
{
    char* c[] = { "ENTER","NEW","POINT","FIRST" };
    char** cp[] = { c + 3,c + 2,c + 1,c };
    char*** cpp = cp;
    printf("%s\n", **++cpp);//++cpp向下移动1,*++cpp找到c+2,**++cpp通过c+2,找到c里的P,最终通过地址打印出POINT
    //前置++cpp保存了位置
    printf("%s\n", *-- * ++cpp + 3);//++cpp再上一个基础上往下移动一个,*++cpp找到cp里的c+1,
    //又因为--,所以c+1变成c,*--*++cpp找到c里的E,但因为+3,所以跳过ENT找到E,打印ER
    //cpp保存了位置
    printf("%s\n", *cpp[-2] + 3);//cpp[-2]->*(cpp-2),*cpp[-2]->**(cpp-2),cpp-2向上局部类型移动2,*(cpp-2)指向cp的c+3,
    //**(cpp-2)找到c里的F,+3跳过FIR从ST开始打印,ST
    //没保存还是用第二个保存的位置
    printf("%s\n", cpp[-1][-1] + 1);//cpp[-1]->*(cpp-1) ,cpp[-1][-1]->*(*(cpp-1)-1),cpp-1向上移动一个,
    //通过*(cpp-1)找到cp里的c+2,因为-1,所以c+2变成c+1,然后*(*(cpp-1)-1)指向c里的c+1,找到N,通过+1,跳过一个地址字符,打印EW

    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值