一.指针练习题
练习1:看图中代码,说出打印结果
下图内存中数字都是以16进制形式书写
分析:int *ptr1 = (int *)(&a + 1);,&a表示整个数组的地址,+1表示跳过整个数组后的地址,(int*)强制类型转换后赋值给ptr1,如上图所示ptr1指向数组末端。ptr1[-1]等价于*(ptr1-1),由于ptr1指针类型是int*,所以-1步长是4byte,即4个内存单元,所以指向的就是元素4,解引用就是4,%x表示以16进制形式打印,且高位不要0,所以打印结果是4
int *ptr2 = (int *)((int)a + 1);,a表示数组首元素的地址,(int)a强制类型转换后,+1只会跳过1个字节,赋值给ptr2,如图所示ptr2指向第二个字节,由于ptr2是int*类型,解引用权限是4byte,所以从第二个字节开始往后数4byte,由于是小端存储模式,所以倒着取,结果是02 00 00 00,%x表示以16进制形式打印,且高位不要0,所以打印结果是2 00 00 00
以上是按小端存储模式来的,如果是大端存储模式,同理,结果应该是00 00 01 00,打印是100
练习2:以下代码的打印结果是
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;
}
图解:
分析:&p[4][2],p是整型数组指针,类型是int (*)[4],*(p+i);(i=0;i++)会出现一个每行4个元素的重构二维数组(以下简称arr,arr相当于把数组a的结构重新排列了),a代表二维数组a的首元素地址,即第一行整个一维数组的地址,类型是int (*)[5],,所以如上图p指向首元素,p[4][2] 等价于*(*(p+4)+2),p+4就是跳过4个int[4],*(p+4)即p[4]代表arr第5行的一维数组的数组名,即arr第5行首元素地址,*(p+4)+2代表arr第5行第3个元素的地址,*(*(p+4)+2)代表arr第5行第3个元素,再&取地址即指向上图蓝色方块处。(注:实际上重构二维数组arr不会出现,只是为了好理解,想象出来的)
而&a[4][2]即数组a第5行第三个元素的地址,指向上图红色方块处。
地址-地址得到的是地址之间的元素个数,如上图红蓝之间是4个元素,但蓝是低地址,红是高地址,所以蓝-红结果是-4。
%p是以地址的16进制原码形式打印,且因为地址是没有负数的,所以会将要打印的数据的补码当成无符号数,也就是把补码当成原码打印,打印结果是FF FF FF FC
%d打印结果就是-4
练习3:看图中代码,说出打印结果
分析:*(ptr1 - 1),&a代表整个二维数组的地址,&a+1跳过整个二维数组,如图指向的位置 ,ptr1-1,即往前跳过1个整型,即10的地址。所以*(ptr1 - 1)结果就是10;
*(ptr2 - 1),a代表二维数组首元素地址,即整个第一行的地址,a+1代表整个第二行的地址,*(a+1)代表整个第二行的数组名,代表第二行首元素的地址,如上图指向位置。ptr2-1,即往前跳过一个整型,即5的地址,所以*(ptr2 - 1)结果是5
练习3:看图中代码,说出打印结果
分析:a是一个指针数组,存放的是char*类型的指针,即"work“首字符'w'的地址、"at"首字符'a'的地址,"alibaba"首字符'a'的地址。单独是数组名a代表首元素地址,即'w'的地址的地址,pa是一个二级指针,存的就是'w'的地址的地址,pa++执行一次,跳过一个char*,指向第二个char*,*pa代表第二个char*,即"at"首字符'a'的地址。
printf("%s\n", *pa);此库函数的第一个参数"%s\n"代表第二个参数需要的是地址,从此地址开始往后打印字符直至遇到'\0'截止('\0'的ASCII码值是0),这里传的参数就是"at"首字符'a'的地址,"at"后面隐藏了一个'\0',所以打印结果是at
练习4:看图中代码,说出打印结果
重点:(1)学会画图分析(2)自增自减会改变cpp自身的值(3)*cpp[-2]等价于*(*(cpp-2))
(4)操作符优先级:解引用 * > 加号+(5)常量字符串后隐藏有'\0'
二.字符串函数练习题
练习1:模拟实现strcpy函数
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
//模拟实现库函数strcpy
char* my_strcpy(char* str2 , const char* str1)
{
char* ret = str2;
assert(str1 && ret);
while (*ret++ = *str1++)
{
;
}
return str2;
}
int main()
{
char arr1[] = "abcdef";
char arr2[10] = { 0 };
my_strcpy(arr2,arr1);
printf("%s\n", arr2);
return 0;
}
练习2:模拟实现strcat函数
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
//模拟实现库函数strcat
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
//首先找目标字符串结尾'\0'
while (*dest)
{
dest++;
}
//追加
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "bit";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
}
练习3:模拟实现strcmp函数
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 != 0 &&*str1++ == *str2++)
{
//if (*str1 == 0)
//{
// return 0;//相等
//}
//str1++;
//str2++;
}
return *str1 - *str2;//不相等
}
int main()
{
char arr1[] = "abcd";
char arr2[] = "abcde";
int ret = my_strcmp(arr1, arr2);
if (ret == 0)
{
printf("==");
}
else if (ret < 0)
{
printf("<"