关于数组和指针比较经典的题目

题目1如下

#include<stdio.h>
#include<stdlib.h>
int main(void) 
{  
   int a[5]={1,2,3,4,5};  
   int *ptr=(int *)(&a+1);   
   printf("%d,%d",*(a+1),*(ptr-1)); 
   return 0;
} 

输出结果为:2,5

在这里主要是考察对指针加减操作的理解

对指针进行加1操作,得到的是下一个元素的地址,而不是在原来指针基础上直接加1,一个类型为T的指针的移动,是以sizeof(T)为单位移动的

首先a的实际类型为int [5],因此对于(int *)(&a+1)而言,先取数组a的首地址,然后进行加1操作,即&a+5*sizeof(int),然后强制转化为整数型指针,此时该指针已经越界,相当于指向a[5],因此ptr实际上等于a+5,所以*(ptr-1)实际上取的是a[4]。

对于*(a+1)来说,就比较简单,先取a的首地址然后指向下一个元素在取值即a[1],这就在于a和&a虽然值相同,但是表达的意义却完全不同,a代表数组首元素的首地址,&a代表数组的首地址。

(int *)(&a+1)     int *

a+1                   int [5]

&a+1                 int [5]*

&a                     int [5]*

a                       int[5]

题目2如下:

#include<stdio.h>
#include<stdlib.h>
int main(void) 
{  
   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;
} 

有了上面一题的基础,很显然可以得出ptr1[-1]的值为4,此处ptr1[-1]等价于*(ptr1-1),

对于第二个输出,首先要弄清楚ptr2的指向,首先(int)a+1表示的值为元素a[0]的第二个字节的地址,然后把这个地址强制转化为(int *)赋给ptr2,在内存布局图中可以看清指向:

在自己电脑中数据以小端模式进行存储,即0x01 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x03 0x00 0x00 0x00 0x04 0x00 0x00 0x00

因此得到的数据就是0x2000000

题目3

#include "stdio.h"

int main()
{
    int a[5][5];
    int (*p)[4];
    p=(int(*)[4])a;
    printf("a_ptr=%#p,p_ptr=%#p
",&a[4][2],&p[4][2]);
    printf("%p,%d
",&p[4][2] - &a[4][2],&p[4][2] - &a[4][2]);
    return 0;
}

本题考察的是二维数组的内存问题和数组指针的问题&p[4][2] - &a[4][2]的值为-4。

首先a表示的是数组首元素的首地址,那么a[i][j]元素的首地址为a+i*sizeof(int)*5+j*sizeof(int),以指针的形式表示即为*(*(a+i)+j),则&[4][2]=&a[0][0]+4*5*sizeof(int)+2*sizeof(int)

p是一个指向包含四个元素的数组的指针,则p+1表示指针向后移动了一个“包含四个整型元素的数组”,基本单位为sizeof(int)*4,那么&p[4]=&a[0][0]+4*4*sizeof(int),&p[4][2]=&a[0][0]+4*4*sizeof(int)+2*sizeof(int).

用内存布局能够更清楚的表达出存储关系:

原文地址:https://www.cnblogs.com/lijumiao/p/3629238.html