指针练习题笔试题

1. 指针笔试题

指针笔试题

  • 题1
int main(int argc, const char * argv[])
{
    int a[5] = {1,2,3,4,5};
    int *p = (int *)(&a+1); // p指向5后面的那个地址
    printf("%d,%d\n", *(a+1), *(p-1));  //2,5
    
    return 0;
}
  • 题2
struct test
{
    int Num;
    char *pcName;
    shortsDate;
    char cha[2];
    shortsBa[4];
}*p;
假设结构体test的大小为20个字节,p的地址为0x100000。
p + 0x1 = ?	// p+1 => +20
(unsigned long)p + 0x1 = ?	// 0x100001 (eg: int a = 0, a + 1 = 1)
(unsigned int *)p + 0x1 = ?	// 0x100004 (加一个指针的大小,32位平台下4)
  • 题3
int main()
{
    int a[4] = {1,2,3,4};
    int *p1 = (int *)(&a+1);
    int *p2 = (int *)((int)a+1);
    printf("%x,%x\n", p1[-1], *p2);
    // p1[-1] 输出 4
    // *p2 这个编译可以通过,但是运行错误
    return 0;
}

在内存中:

指针笔试题3

  • 题4
int main()
{
    int a[3][2] = { (0,1), (2,3), (4,5) };
    int *p = a[0];
    printf("%d\n", p[0]); // 输出1
    
    return 0;
}

注意逗号表达式:运算结果为后面的值

所以:

4

  • 题5
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]); //输出: -4的补码,-4
    
    return 0;
}

5

输出他们之间元素的个数。

因为p[4][2]的地址小于a[4][2]的地址,所以为-4,但是由于输出的时候,%p输出的是地址,也就是一个无符号的数,所以将-4的补码输出,%d正常输出。

  • 题6
int main()
{
    int aa[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
    int *p1 = (int *)(&aa + 1);
    int *p2 = (int *)(*(aa + 1));
    printf("%d,%d\n", *(p1-1), *(p2-1));	// 输出10,5
    
    return 0;
}

&aa+1跨过了整个数组aa的长度,指向元素10后的地址。

aa+1代表的跨过了一个aa的元素,而aa是一个二维数组,它的元素是一个一维数组。

如图:

6

  • 题7
int main()
{
    char *a[] = {"work", "at", "360"};
    char **pa = a;
    pa++;
    printf("%s\n", *pa);	// 输出at
    
    return 0;
}

7

  • 题8
int main()
{
    char *c[] = { "ENTER", "NEW", "POINT", "FIRST" };
    int **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;
}

++、—的优先级高于**的优先级高于+

++cpp会影响cpp的值,但cpp+1不会影响。

[]的优先级大于*

8.1

**++cpp:先++,此时的cpp指向cp[1],解引用为c[2],再解引用即为POINT

8.2

*--*++cpp+3:经过上一步,cpp现在的指向如上图。

++,此时cpp指向cp[2],解引用即为cp[2],再--,此时改变了cp[2]的指向,他指向c[0],再解引用即为c[0],给c[0]+3,输出的结果为ER

8.3

*cpp[-2]+3:经过上一步,现在的指向如上图所示。

cpp[-2]指向了cp[0],解引用指向c[3]c[3]+3输出ST

cpp[-1][-1]+1:经过上一步并没有改变指针的指向。

cpp[-1][-1]代表c[1],再+1输出EW




2. 大量的sizeof()和strlen()练习,加深理解数组和指针

2.1)一维数组

int main(int argc, const char * argv[])
{
    // 一维数组
    int a[] = {1,2,3,4};
    printf("----------\n");
    printf("%p\t->\ta[0]\t->\t%d\n", &a[0], a[0]);
    printf("%p\t->\ta[1]\t->\t%d\n", &a[1], a[1]);
    printf("%p\t->\ta[2]\t->\t%d\n", &a[2], a[2]);
    printf("%p\t->\ta[3]\t->\t%d\n", &a[3], a[3]);
    printf("----------\n");
    printf("sizeof(a)\t->\t%lu\n", sizeof(a));//a代表整个数组,16
    printf("sizeof(a+0)\t->\t%lu\n", sizeof(a+0));//a+0代表的是数组首元素的地址,&a[0],这里32位输出4,64位输出8。
//    printf("a+0\t->\t%p\n", a + 0);
//    printf("a\t->\t%p\n", a);
    printf("sizeof(*a)\t->\t%lu\n", sizeof(*a));//*a是数组第一个元素,4
//    printf("*a\t->\t%d\n", *a);
    printf("sizeof(a+1)\t->\t%lu\n", sizeof(a+1));//a+1代表数组第二个元素的地址,&a[1],8
//    printf("%p\n", a+1);
    printf("sizeof(a[1])\t->\t%lu\n", sizeof(a[1]));//a[1]的大小,4
    printf("sizeof(&a)\t->\t%lu\n", sizeof(&a));//数组的地址,8
//    printf("%p\n", &a);
    printf("sizeof(*&a)\t->\t%lu\n", sizeof(*&a));//*和&抵消,相当于a代表整个数组,16
    printf("sizeof(&a+1)\t->\t%lu\n", sizeof(&a+1));//这个是个地址,跨过了16个字节,8
//    printf("%p\n", &a+1);
    printf("sizeof(&a[0])\t->\t%lu\n", sizeof(&a[0]));//8
    printf("sizeof(&a[0]+1\t->\t%lu\n", sizeof(&a[0]+1));//&a[1]
//    printf("%p\n", &a[0]+1);
    
    
    return 0;
}

2.2)字符数组

int main()
{
    char a[] = {'a', 'b', 'c', 'd', 'e', 'f'};
    printf("----------\n");
    printf("%p\t->\ta[0]\t->%c\n", &a[0], a[0]);
    printf("%p\t->\ta[1]\t->%c\n", &a[1], a[1]);
    printf("%p\t->\ta[2]\t->%c\n", &a[2], a[2]);
    printf("%p\t->\ta[3]\t->%c\n", &a[3], a[3]);
    printf("%p\t->\ta[4]\t->%c\n", &a[4], a[4]);
    printf("%p\t->\ta[5]\t->%c\n", &a[5], a[5]);
    printf("----------\n");
    printf("sizeof(a)\t->\t%d\n", sizeof(a));//a表示整个数组,6
    printf("sizeof(a+0)\t->\t%d\n", sizeof(a+0));//表示&a[0],8
//    printf("%p\n", a+0);
    printf("sizeof(*a)\t->\t%d\n", sizeof(*a));//*a表示a[0],1
//    printf("%c\n", *a);
    printf("sizeof(a[1])\t->\t%d\n", sizeof(a[1]));//a[1],1
    printf("sizeof(&a)\t->\t%d\n", sizeof(&a));//数组的地址,8
//    printf("%p\n", &a);
    printf("sizeof(&a+1)\t->\t%d\n", sizeof(&a+1));//字符f(a[5])后面的那个元素的地址,跨越了一个a的长度,8
//    printf("%p\n", &a+1);
    printf("sizeof(&a[0]+1)\t->\t%d\n", sizeof(&a[0]+1));//字符b的地址,8
//    printf("%c\n", *(&a[0]+1));
    printf("----------------\n");
    printf("strlen(a)\t->\t%d\n", strlen(a));//这个不确定是多少,strlen是以\0为标志计算的,不知道a数组完后是否为'\0'
    printf("strlen(a+0)\t->\t%d\n", strlen(a+0));
//    printf("strlen(*a)\t->\t%d\n", strlen(*a));//ERROR!strlen()的参数类型为char*的
//    printf("strlen(a[1])\t->\t%d\n", strlen(a[1]));//ERROR!strlen()的参数类型为char*的,做如下行的修改
    printf("strlen(a[1])\t->\t%d\n", strlen(&a[1]));//OK
    printf("strlen(&a)\t->\t%d\n", strlen(&a));//6
    printf("strlen(&a+1)\t->\t%d\n", strlen(&a+1));//这个是不确定的
    printf("strlen(&a[0]+1)\t->\t%d\n", strlen(&a[0]+1));//5

    return 0;
}

2.3)字符串数组

int main()
{
    char a[] = "abcdef";
        printf("----------\n");
        printf("%p\t->\ta[0]\t->%c\n", &a[0], a[0]);
        printf("%p\t->\ta[1]\t->%c\n", &a[1], a[1]);
        printf("%p\t->\ta[2]\t->%c\n", &a[2], a[2]);
        printf("%p\t->\ta[3]\t->%c\n", &a[3], a[3]);
        printf("%p\t->\ta[4]\t->%c\n", &a[4], a[4]);
        printf("%p\t->\ta[5]\t->%c\n", &a[5], a[5]);
        printf("----------\n");
        printf("sizeof(a)\t->\t%d\n", sizeof(a));//7,字符数组长度,算\0
        printf("sizeof(a+0)\t->\t%d\n", sizeof(a+0));//8,第一个元素的地址
        printf("sizeof(*a)\t->\t%d\n", sizeof(*a));//1,第一个元素的大小
        printf("sizeof(a[1])\t->\t%d\n", sizeof(a[1]));//1
        printf("sizeof(&a)\t->\t%d\n", sizeof(&a));//8,地址
        printf("sizeof(&a+1)\t->\t%d\n", sizeof(&a+1));//8,地址(是'\0'后面的那个字符的地址)
        printf("sizeof(&a[0]+1)\t->\t%d\n", sizeof(&a[0]+1));//8,是a[1]的地址
        printf("----------------\n");
        printf("strlen(a)\t->\t%d\n", strlen(a));//6,字符串长度,不算\0
        printf("strlen(a+0)\t->\t%d\n", strlen(a+0));//6
//        printf("strlen(*a)\t->\t%d\n", strlen(*a));//ERROR!
//        printf("strlen(a[1])\t->\t%d\n", strlen(a[1]));//ERROR!
        printf("strlen(&a[1])\t->\t%d\n", strlen(&a[1]));//5
        printf("strlen(&a)\t->\t%d\n", strlen(&a));//6
        printf("strlen(&a+1)\t->\t%d\n", strlen(&a+1));//0
        printf("strlen(&a[0]+1)\t->\t%d\n", strlen(&a[0]+1));//5

    return 0;
}

2.4)字符串常量

int main()
{
    char *p = "abcdef";
    printf("--------\n");
    printf("%p -> p[0] -> %c\n", &p[0], p[0]);
    printf("%p -> p[1] -> %c\n", &p[1], p[1]);
    printf("%p -> p[2] -> %c\n", &p[2], p[2]);
    printf("%p -> p[3] -> %c\n", &p[3], p[3]);
    printf("%p -> p[4] -> %c\n", &p[4], p[4]);
    printf("%p -> p[5] -> %c\n", &p[5], p[5]);
    printf("--------\n");
    printf("%d\n", sizeof(p));//8,字符常量的地址
    printf("%d\n", sizeof(p+1));//8,b字符的地址地址
//    printf("%c\n", *(p+1));
    printf("%d\n", sizeof(*p));//1,首元素的大小
    printf("%d\n", sizeof(p[0]));//1,首元素的大小
    printf("%d\n", sizeof(&p));//8,字符常量的地址
    printf("%d\n", sizeof(&p+1));//8,这个并不是字符b的地址,是\0后面元素的地址
    printf("%d\n", sizeof(&p[0]+1));//8,字符b的地址大小
    printf("---------\n");
    printf("%d\n", strlen(p));//6,字符串长度
    printf("%d\n", strlen(p+1));//5,从b开始往后数字符串的长度
//    printf("%d\n", strlen(*p));//ERROR!需要传入一个char *
//    printf("%d\n", strlen(p[0]));//ERROR!和上面一样
    printf("%d\n", strlen(&p));//这个值是不确定的,p不是数组,传入后会从p的地址往后一个字节一个字节的找,遇到\0停下
    printf("%d\n", strlen(&p+1));//不确定
    printf("%d\n", strlen(&p[0]+1));//5,从字符b开始往后数


    return 0;
}

2.5)二维数组

int main()
{
    int a[3][4] = {0};
    printf("-------\n");
    printf("%p -> a[0][0] -> %d\n", &a[0][0], a[0][0]);
    printf("%p -> a[3][4] -> %d\n", &a[3][4], a[3][4]);
    printf("&a[3][4] - &a[0][0] = %d\n", &a[3][4]-&a[0][0]);//一共有多少个元素
    printf("3 行 4 列\n");
    printf("-------\n");
    printf("%d\n", sizeof(a));//48,16个元素,每个元素占4个字节
    printf("%d\n", sizeof(a[0][0]));//4,第一个元素的大小
    printf("%d\n", sizeof(a[0]));//16,第一行元素的大小
    printf("%d\n", sizeof(a[0]+1));//8,a[0]是数组名,+1即为下一个元素的地址,a[0]+1 <=> a[0][1]
//    printf("%p\n", a[0]+1);
    printf("%d\n", sizeof(*(a[0]+1)));//4,a[0][1]的大小(int)
    printf("%d\n", sizeof(a+1));//8,第二个元素的地址,即&a[1]
    printf("%d\n", sizeof(*(a+1)));//16,第二行元素,相当于sizeof(a[1])
    printf("%d\n", sizeof(&a[0]+1));//8,第二行数组的地址,相当于a+1
    printf("%d\n", sizeof(*(&a[0]+1)));//16,相当于a[1]
    printf("%d\n", sizeof(*a));//16,相当于a[0]
    printf("%d\n", sizeof(a[3]));//16,虽然越界了,但是还是当前数组的类型

    return 0;
}




EOF,如有不足请指正!

发布了73 篇原创文章 · 获赞 90 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Hanoi_ahoj/article/details/84558748