1.考察指针运算
#include <stdio.h>
void main()
{
int TestArray[5][5] = { {11,12,13,14,15},
{16,17,18,19,20},
{21,22,23,24,25},
{26,27,28,29,30},
{31,32,33,34,35}
};
int* p1 = (int*)(&TestArray + 1);
int* p2 = (int*)(*(TestArray + 1) + 6);
printf("Result: %d; %d; %d; %d; %d\n", *(*TestArray), *(*(TestArray + 1)),
*(*(TestArray + 3) + 3), p1[-8],
p2[4]);
}
结果是11,16,29,28,26
提示:
(1)&TestArray不仅是数组首地址,而且还包含了内存大小信息,&TestArray+1之后指向的是数组最后一个元素的后面。
(2)数组和指针运算的转换:*(a+i) ==> a[i] ,* (*(a+i)+j)==>a[i][j];
2.考察调试经验
#include<stdio.h>
void main()
{
char* p = "hello world!";
int a = (int)p;
short s = 'c';
printf("%c\n", (long)(*((int*)p)));
printf("%s\n", a);
printf("%s\n", &s);
}
输出的结果是
h
hello world!
c
你可能会疑惑,和想象输出的结果不一样,其实这主要是printf函数的第二个输入参数是可变参数的原因,可变参数函数无法确定参数的实际类型,可以看一下之前的这篇文章:
C语言函数参数的秘密(下)
分析:
1.首先,( * ((int*)p)),得到的是四个字节,hell,%c只取一个字节打印,所以打印了h。
2.变量a是四个字节,刚好存放了字符串的地址,%s打印的是字符串,因此后面的地址被printf解释为字符串的地址,打印出了字符串。
3.&s存放的是2个字节的地址,字符’c’一个字节,小端系统上内存存放方式是c0,大端系统存放的是0c,小端系统低地址放低位,先放低字节,再放高字节,即c0。
3.考察安全编程
#include<stdio.h>
int main(int argc, char *argv[])
{
int flag = 0;
char passwd[10];
memset(passwd,0,sizeof(passwd));
strcpy(passwd, argv[1]);
if(0 == strcmp("Linuxpswd", passwd))
{
flag = 1;
}
if( flag )
{
printf("\n Password cracked \n"); //密码正确输出这个
}
else
{
printf("\n Incorrect passwd \n"); //密码错误输出这个
}
return 0;
}
这定义的密码passwd是九位数,那么超过十位数会发生什么呢?
数组越界,将密码越界错误之后,第一次输出了错误,但是第二次输入任意的密码,居然输出了密码正确。
int flag = 0; 和 char passwd[10]; 都是定义在栈上面的,初始化的时候,flag是0,然后经过字符串拷贝函数strcpy(passwd, argv[1]); 之后呢,如果数组越界了那么flag空间的内容就会被改写了,falg就不是0了,如果是一个非零值,那么会输出密码正确。
所以最好使用strncpy这个函数,而不是strcpy使用零作为结束符,如果将strcpy(passwd, argv[1]);改写为`strncpy(passwd, argv[1],9); ,那么就可以避免这个问题了,限制密码拷贝为9个字符,更加安全。

本文介绍了三道C语言面试题目,分别涉及指针运算、调试经验和安全编程。在指针运算中,分析了数组与指针的关系;调试经验部分通过一个实例展示了printf函数的可变参数特性;安全编程环节讨论了数组越界导致的隐患,并提出使用strncpy代替strcpy来避免此类问题。

被折叠的 条评论
为什么被折叠?



