C语言数组指针加1的问题

C语言数组指针加1的问题,第1张

目录

1. 用C++语言测试

2. 用汇编语言测试(MASM环境)


指向数组的指针存储的是连续的内存地址,而内存地址的最小编址单位是1字节,如果存储的数据本身移动几个字节,则内存地址也相应地移动几个字节。而数组指针的加1移动几个字节,取决于所指向的数组类型,这部分是由C/C++的编译器实现去处理的。下面具几个例子说明(下面的例子在MSVC的X64平台,指针本身占8个字节):

1. 用C++语言测试

(1) 指向1字节的数组指针:

void TestPointerSize()

{

    char data[] = {1,2,3,4,5,6,7,8,9,10};

    char* ptr = data;

    printf("ptr size=%d,data=%I64d\n",sizeof(ptr),data);

    for(int i=0;i<10;i++)

    {

        printf("data[%d]=%d,ptr=%I64d\n",i,*ptr,ptr);  

        ptr = ptr + 1;

    }

}

输出如图:

从图中可以看到,指针本身的大小占8个字节,数组名是数组的首地址,常量指针。但注意,sizeof(data)是计算整个数组的存储大小,而不是首地址的大小。指针每次加1,也是加1字节长度即1个数组元素的大小

(2) 指向2字节的数组指针:

void TestPointerSize()

{

    short data[] = {1,2,3,4,5,6,7,8,9,10};

    short* ptr = data;

    int n = sizeof(data);

    printf("ptr size=%d,data=%I64d\n",sizeof(ptr),data);

    for(int i=0;i<10;i++)

    {

        printf("data[%d]=%d,ptr=%I64d\n",i,*ptr,ptr);  

        ptr = ptr + 1;

    }

}

输出如图:

可以看到,指针每次加1,是加2字节长度即1个数组元素的大小

(3) 指向4字节的数组指针:

void TestPointerSize()

{

    int data[] = {1,2,3,4,5,6,7,8,9,10};

    int* ptr = data;

    int n = sizeof(data);

    printf("ptr size=%d,data=%I64d\n",sizeof(ptr),data);

    for(int i=0;i<10;i++)

    {

        printf("data[%d]=%d,ptr=%I64d\n",i,*ptr,ptr);  

        ptr = ptr + 1;

    }

}

输出如图:

可以看到,指针每次加1,是加4字节长度即1个数组元素的大小

(4) 指向8字节的数组指针:

void TestPointerSize()

{

    __int64 data[] = {1,2,3,4,5,6,7,8,9,10};

    __int64* ptr = data;

    int n = sizeof(data);

    printf("ptr size=%I64d,data=%I64d\n",sizeof(ptr),data);

    for(int i=0;i<10;i++)

    {

        printf("data[%d]=%I64d,ptr=%I64d\n",i,*ptr,ptr);   

        ptr = ptr + 1;

    }

}

输出如图:

可以看到,指针每次加1,是加8字节长度即1个数组元素的大小

2. 用汇编语言测试(MASM环境)

(1) 指向1字节的数组指针:

汇编声明一个数组:

.const

   data_ byte 1,2,3,4,5,6,7,8,9,10

C++下声明一个访问数组元素的函数,并用汇编实现

extern "C" int GetArrayItem(int i,char* ptr);

汇编语言实现:

    .code

GetArrayItem proc

    ; Make sure 'i' is valid

    cmp ecx,0

    jl InvalidIndex ;jump if i < 0

    cmp ecx,[NumFibVals_]

    jge InvalidIndex ;jump if i >= NumFibVals_

    ; Sign extend i for use in address calculations

    ;mov rax,offset data_ ;get

    lea rbx,data_  ;取得数组的偏移地址,我们可以理解为取得数组的地址,也可换成offset伪指令

    xor rax,rax

    mov eax,ecx

    imul eax,1   ;i的值乘以数据的大小,这里是1字节

    movsxd rax,eax  ;符号扩展到64位

    add rbx,rax ;得到数组的偏移地址

    mov eax,[rbx] ;取得偏移地址指向的内存存储的值

    mov [rdx],eax  ;将值复制到外部传入的指针所指示的内存地址

    mov eax,1 ;set success return code

    ret

    InvalidIndex:

    xor eax,eax ;set error return code

    ret

GetArrayItem endp

end

调用代码:

void TestPointerSize()

{

    char* ptr = (char*)malloc(sizeof(char));

    for(int i=0;i<10;i++)

    {

        GetArrayItem(i,ptr);

        printf("data[%d]=%d\n",i,*ptr);

    }

free(ptr);

}

输出结果如图:

 

(2) 指向2字节的数组指针:

汇编声明一个数组:

.const

    data_ word 2001,2002,2003,2004,2005,2006,2007,2008,2009,2010

汇编访问代码改一句:

imul rbx,2   ;i的值乘以数据的大小,现在这里是2字节

改调用函数:

extern "C" int GetArrayItem(int i,short* ptr);

调用代码:

void TestPointerSize()

{

    short* ptr = (short*)malloc(sizeof(short));

    for(int i=0;i<10;i++)

    {

        GetArrayItem(i,ptr);

        printf("data[%d]=%d\n",i,*ptr);

    }

   free(ptr);

}

输出结果如图:

(3) 指向4字节的数组指针:

汇编声明一个数组:

.const

    data_ dword 3001,3002,3003,3004,3005,3006,3007,3008,3009,3010

汇编访问代码改一句:

imul rbx,4   ;i的值乘以数据的大小,现在这里是4字节

改调用函数:

extern "C" int GetArrayItem(int i,int* ptr);

调用代码:

void TestPointerSize()

{

    int* ptr = (int *)malloc(sizeof(int));

    for(int i=0;i<10;i++)

    {

        GetArrayItem(i,ptr);

        printf("data[%d]=%d\n",i,*ptr);

    }

   free(ptr);

}

输出结果如图:

(4) 指向8字节的数组指针:

汇编声明一个数组:

.const

    data_ qword 8001,8002,8003,8004,8005,8006,8007,8008,8009,8010

汇编访问代码:

GetArrayItem proc

    ; Make sure 'i' is valid

    cmp ecx,0

    jl InvalidIndex ;jump if i < 0

    cmp ecx,[NumFibVals_]

    jge InvalidIndex ;jump if i >= NumFibVals_

    ; Sign extend i for use in address calculations

    ;mov rax,offset data_ ;get

    lea rbx,data_  ;取得数组的偏移地址,我们可以理解为取得数组的地址,也可换成offset伪指令

    xor rax,rax

    mov eax,ecx

    imul eax,8  ;i的值乘以数据的大小,这里是8字节

    movsxd rax,eax ;符号扩展到64位

    add rbx,rax ;得到数组的偏移地址

    mov rax,[rbx] ;取得偏移地址指向的内存存储的值

    mov [rdx],rax  ;将值复制到外部传入的指针所指示的内存地址

    mov eax,1 ;set success return code

    ret

    InvalidIndex:

    xor eax,eax ;set error return code

    ret

GetArrayItem endp

改调用函数:

extern "C" int GetArrayItem(int i,__int64* ptr);

调用代码:

void TestPointerSize()

{

    __int64* ptr = (__int64*)malloc(sizeof(__int64));

    for(int i=0;i<10;i++)

    {

        GetArrayItem(i,ptr);

        printf("data[%d]=%d\n",i,*ptr);

    }

   free(ptr);

}

输出结果如图:

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/785914.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-04
下一篇 2022-05-04

发表评论

登录后才能评论

评论列表(0条)

保存