指针相关笔面试题解析
Suzhou 47 1
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

上述代码第4行,&a取出的是数组的地址,+1后仍是数组地址,类型是数组指针类型,数组指针类型存进整型指针时需要强制类型转换


//已知结构体Test类型的变量大小是20字节
struct Test 
{
    int Num;
    char* pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}* p;  
//结构体指针创建p变量

int main()
{
    p = (struct Test*)0x100000;
    printf("%p\n", p + 0x1);  //0x1是16进制的1,和10进制的1值一样
    printf("%p\n", (unsigned long)p + 0x1);  //整型类型(整数)+1就是原来值+1
    //指针类型先转10进制类型再+1
    printf("%p\n", (unsigned int*)p + 0x1);
    //unsigned int*无符号整型指针,+1跳过一个无符号整型(4字节)
    return 0;
} 
0000000000100020
0000000000100001
0000000000100004

::: tip 指针±整数运算,±的具体数字取决于指针类型。 :::


int main()
{
    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]相当于 * (ptr1-1),ptr1是int*类型,大小为4字节,ptr1-1为4的地址,解引用得到4,即ptr1[-1]=4。 (int)a表示将数组a首元素地址强制类型转换成int,整数+1就是数字+1,然后再当作地址,相当于向后移动一个字节,ptr2的位置是图中红圈标识位置,小端存储模式下,还原为地址是0x02000000的地址,解引用后最前面的0省略,为0x2000000。 ::: warning 内存中最小内存单位是1字节,每个字节都有一个地址,即两个相邻地址相差一个字节。 :::


int main()
{
    int a[3][2] = { (0,1),(2,3),(4,5) };
    int* p;
    p = a[0];
    printf("%d", p[0]);
    return 0;
}

上述代码中a[3][2]的赋值是3个逗号表达式,取最后一个值,即a[3][2]={1,3,5}; 指针相关笔面试题解析 如上图,a[0]是第一行的数组名,没有单独放在sizeof和&后面,表示第一行数组的首元素地址即“1”的地址。p[0]==*(p+0)。p是“1”的地址,+0后不变,解引用得到“1”。


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;
}

int(* p)[4];可得p是指向有4个整型元素的数组的指针。将a赋给p即a[0]数组的地址赋给p,赋值时会有警告,原因是p的类型是int(* )[4],a的地址是a[5]的地址,类型是int()[5]。可以忽略警告强行赋值。 *p[4] == * (p+4)** p[4][2] == *( *(p+4)+2)· ::: warning

int main()
{
    int arr[] = { 1,2,3,4,5 };
    int* p = arr;
    *(p + 2) == arr[2];
    *(p + 2) == *(arr + 2);
    *(arr + 2) == arr[2];
    return 0;
}

上述代码中第5行 * (p + 2)和arr[2]值相等,第4行可得出第6行,即 * (arr + 2) == arr[2]。 ::: p是int(*)[4]类型的指针,p+1就会跳过一个4个int类型元素的数组。 p+4指向的是数组a[3]中第二个元素的地址,p是指向数组的指针,解引用拿到的是上图中红框中四个元素的数组,相当于拿到了这四个元素的数组名,就是这四个元素的数组的首元素地址。 指针相关笔面试题解析 &p[4][2]对p[4][2]取地址,即上图 * (p+4)+2的位置。 指针相减得到的是指针之间的元素个数,如上图所示,&p[4][2]和&a[4][2]之间有4个元素,&p[4][2]在内存中的位置小于&a[4][2],结果为-4。 计算结果以%d的形式打印,输出-4。以%p的形式打印,结果是FFFFFFFC。 ::: tip -4的输出:

10000000000000000000000000000100 - -4原码
11111111111111111111111111111011 - -4反码
11111111111111111111111111111100 - -4补码

以%d的形式打印时,需要-4的原码,即-4。 以%p的形式打印时,认为内存中存放的是地址,地址不存在原反补和正负的区别,就会直接打印内存中存放的内容,即11111111111111111111111111111100 :::


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));  //10,5
    return 0;
}

上述代码第5行 * (aa + 1)就是aa[1],表示第二行元素组成数组的地址即“6”的地址(也可以理解成二维数组aa表示首元素地址即第一行元素地址,+1跳过第一行,指向第二行的第一个元素即“6”的地址)。


int main() 
{
    char* a[] = { "work", "at", "alibaba"};
    char** pa = a; 
    pa++;
    printf("%s\n", *pa);  //at
    return 0;
}

::: warning

char* p = "abcdefg";

上述代码的写法是将常量字符串abcdefg首字符a的地址存放在指针p中。 ::: 数组a的内存布局:数组a中有3个元素,分别是w、a、a的地址,类型都是char * 。 数组名a是首元素地址即w的地址(类型char),存放在pa中(类型char)。 ::: tip char pa = a写法实际上是char * pa = a,* pa的* 表示pa是指针,char表示a是地址。 ::: pa++即pa+1跳过一个char 类型的变量,指向下一个char类型的变量即a的地址。 ::: tip *变量±整数 表示跳过 整数×类型 大小个字节。** ::: %s形式打印时以a的地址开始打印一个字符串,即打印“at”。 指针相关笔面试题解析


int main() {
    char* c[] = { "ENTER","NEW","POINT","FIRST"};
    char** cp[] = { c + 3,c + 2,c + 1,c };
    char*** cpp = cp;
    printf("%s\n", **++cpp);  //POINT
    printf("%s\n", *-- * ++cpp + 3);  //ER
    printf("%s\n", *cpp[-2] + 3);  //ST
    printf("%s\n", cpp[-1][-1] + 1);  //EW
    return 0;
}

指针数组c中存放4个字符指针,即4个字符串的首字符地址。 上述代码第6行,cpp先前置++,然后解引用得到“c+1”,前置--后变为c,再解引用得到“E”的地址,再+3指向字符串“ENTER”中的第二个字符“E”,%s从此处开始向后打印字符串,输出“ER”。 上述代码第7行,cpp[-2] == * (cpp-2),找到“c+3”,再解引用找到“F”的地址,+3向后偏移3个字节指向“S”,%s从此处开始向后打印字符串,输出“ST”。 上述代码第8行,cpp[-1][-1] == * (*(cpp-1)-1),第7行代码中cpp只参与运算不改变本身,cpp仍指向“c+1”,cpp-1指向“c+2”,解引用得到“c+2”,-1后变为“c+1”,解引用得到“N”的地址,+1向后偏移1个字节指向“E”,%s从此处开始向后打印字符串,输出“EW”。 指针相关笔面试题解析 ::: tip cpp自增和自减会改变cpp的值,cpp参与运算不改变cpp本身。 :::


评论区

索引目录