转载http://blog.csdn.net/feitianxuxue/article/details/7334929
前几天天看到这本书,感觉不错,在看之前,先做了后面的习题,结果只得了60多分,一直以为自己的基础还是不错的,做完后对了答案后,感觉自己的自信心一下全没有了,不过遇到问题解决问题,我用了2天时间好好研读了这本书,感觉真不错。虽然感觉都是一些基础的知识,但是我读的还是津津有味,感觉收获蛮多的,感谢这本书的作者陈正冲。呵呵,说来我本科专业和这位大牛还是同一个专业呢,呵呵。不是只有计算机科班出身的才能学好编程,知真正的高手都是自学的。
今天就把我当时做错的题目和认为比较好的题目一个个写出来。再次分析下
如果我在哪家公司遇到类似这种题目我会感觉这家公司出题很有水平,重基础,真正理解C语言的人才能得高分。注重细节,知其然知其所以然。
题目1.
下面代码有什么问题,为什么?
1.#include
2.using namespace std;
3.
4.int _tmain(int argc, _TCHAR* argv[])
5.{
6. char string[10],str1[10];
7. int i;
8. for (i=0;i<10;i++)
9. {
10. str1[i] = 'a';
11. }
12. strcpy(string,str1);
13. cout<<string<<endl;
14. system("pause");
15. return 0;
16.}
运行的时候回出现下面情况:
error1.exe
做这个题目的时候,我也知道字符串strcpy是以'\0'为结束标识的。会产生数组越界,但是表达不清楚。
答案:运行到strcpy的时候可能会产生内存异常。
因为:str1没有结束符标识,str1数组后面继续存储的可能不是'\0',而是乱码。Cout函数,对于输出char*类型,顺序打印字符串中的字符直到遇到空字符('\0')或打印了由精度指定的字符数为止。
题目2.
下面代码的结果是多少?为什么?
1.#include
2.using namespace std;
3.
4.int _tmain(int argc, _TCHAR* argv[])
5.{
6. char a[1000];
7. int i;
8. for (i=0;i<1000;i++)
9. {
10. a[i] = -1-i;
11. }
12. cout<<strlen(a)<<endl;
13.
14. system("pause");
15. return 0;
16.}
做题目的时候没有考虑到字符溢出,自然做错了
分析:
我们知道计算机底层只认识0,1,所以任何数据到了底层都会通过计算转换成0,1,那么负数是怎样存储呢?由于“-”无法存入内存,我们把它做个标记,把基本数据类型的最高位腾出来,用来存符号,同时约定如下:如果最高位是1,表明这个数是负数,其值为除最高位以外的剩余位的值添上这个“-”号。
for循环内,当i的值为0时,a[0]的值为-1.在计算机系统中,数值一律用补码来表示。在用两个补码的数相加时,如果最高位(符号位)有进位,则进位被舍弃。正数的补码与其原码一致;负数的补码:符号位为1,其余位为该数绝对值的原码按位取反,然后整个数+1.
-1的补码为0xff,-2的补码为0xfe......
当i的值为127时,a[127]的值为-128,而-128是char类型数据能表示的最小的负数。
当i继续增加,a[128]的值肯定不能使-129,因为这时候发生了溢出。-129需要9位(1
按照上面的分析,a[0]~a[254]里面的值都不为0,而a[255]的值我0.strlen函数是计算字符串长度的,并不包含字符串最后的'\0'。判断一个字符串是否结束的标志就是看是否遇到'\0';如果遇到'\0',则认为字符串结束。
由此分析,strlen(a)的值为255
题目3.
下面的两段代码有什么区别?什么时候需要使用代码(2)
代码(1):
int
int
int
代码(2):
volatile
int
int
基础知识:
Volatile关键字和const一样,是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素改变,比如操作系统、硬件或者其他线程。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
int
int
int
此时编译器对代码进行优化,这是因为在(1)(2)两条语句中,i没有被用作左值(没有被赋值)。这时候编译器认为i的值没有发生改变,所以在(1)语句时从内存中取出i的值赋给j之后,这个值并没有丢弃掉,而是在(2)语句时继续用这个值给k赋值。编译器不会生成出汇编代码重新从内存里取i的值,这样提高了效率。但是要注意的是:(1)(2)语句之间确认i没有被用作左值才行。
volatile
int
int
volatile
这样看来,如果i是一个寄存器变量,表示一个端口数据或者是多个线程的共享数据,那么就容易出错,所以volatile
题目4.
在32位的x86系统下,输出的值是多少?
1.#include
2.using namespace std;
3.
4.int _tmain(int argc, _TCHAR* argv[])
5.{
6. int a[5] = {1,2,3,4,5};
7. int *ptr1 = (int *)(&a+1);
8. int *ptr2 = (int *)((int)a+1);
9. cout<<hex<<ptr1[-1]<<endl<<hex<<*ptr2<<endl;
10. system("pause");
11. return 0;
12.}
运行结果:5
分析:这里需要注意的是&a是整个数组的首地址,a是数组首元素的首地址,其值相同,但是意义不同。
对于指针p+1,指针变量与一个整数相加减并不是用指针变量里的地址直接加减这个整数,这个整数的单位不是字节而是元素的个数。
知道了这些就好办了。
int
&a+1这下加的1跑到了a[5](虽然不存在),ptr1[-1]=*(ptr1-1),这下跑到了a[4],所以结果是5;
int
a是数组a的首元素的首地址。(int)a+1是元素a[0]的第二个字节的地址。由于是int型,所以占4个字节
大端模式:
0x00
在32位的x86系统下,是小端模式——认为第一个字节是最低位字节
在内存中存放为:
a[0]
0x01
所以读取为:0x02000000
答案为:2000000
题目5.
假设p的值为0x100000,如下表达式的值分别为多少?
1.#include
2.using namespace std;
3.
4.int _tmain(int argc, _TCHAR* argv[])
5.{
6. struct Test
7. {
8. int Num;
9. char *pcName;
10. short sDate;
11. char cha[2];
12. short sBa[4];
13. }*p;
14. p = (Test *)0x100000;
15. cout<<hex<<(p+0x1)<<endl;
16. cout<<hex<<((unsigned long)p+0x01)<<endl;
17. cout<<hex<<((unsigned int *)p+0x01)<<endl;
18. system("pause");
19. return 0;
20.}
运行结果为:
这里还是记住一句话:指针p+1,指针变量与一个整数相加减并不是用指针变量里的地址直接加减这个整数,这个整数的单位不是字节而是元素的个数。
p+0x1的值为0x100000+sizeof(Test)*0x01=0x100014
(unsigned
(unsigned
题目6.
下面代码输出的结果是多少?
1.#include
2.using namespace std;
3.
4.int _tmain(int argc, _TCHAR* argv[])
5.{
6. int a[3][2] = {(0,1),(2,3),(4,5)};
7. int *p;
8. p = a[0];
9. cout<<p[0];
10. system("pause");
11. return 0;
12.}
运行结果:1
这里需要注意的是{}里面是逗号表达式,int
int
题目7.
下面的代码有什么问题?为什么?
1.#include
2.using namespace std;
3.
4.struct student
5.{
6. char *name;
7. int score;
8.}stu,*pstu;
9.
10.int _tmain(int argc, _TCHAR* argv[])
11.{
12. pstu = (struct student *)malloc(sizeof(struct student));
13. strcpy(pstu->name,"Jimy");
14. pstu->score = 99;
15. free(pstu)+;
16. system("pause");
17. return 0;
18.}
运行错误:
error7.exe
为指针变量pstu分配了内存,但是没有给name指针分配内存。
在为结构体指针分配内存的时候,是从外向里,即先分配结构体的指针,再分配成员指针,释放的时候,是从里向外,先释放成员指针,再释放结构体指针,顺序不能错。
正确的修改应该是:
pstu
pstu->name
修正:由于疏忽,这道题没写完,再次把修正后的答案,贴出来,以免误导读者,下面是一个贴友的答案,谢谢!
1.int main(int argc, char* argv[])
2.{
3. pstu = (struct student *)malloc(sizeof(struct student));
4. pstu->name = (char *)malloc(20);
5. strcpy(pstu->name,"Jimy");
6. pstu->score = 99;
7. free(pstu->name);
8. pstu->name = NULL;
9. free(pstu);
10. pstu = NULL;
11. system("pause");
12. return 0;
13.}