如果可能,请加精!谢谢,这样能引起更多的人对编程细节的思考和重视!
没想到引起大家这么热烈的讨论,C语言中确实有许多细节需要大家在编程中共同去揭密的。答案如下(这是我给出的,如果有误,欢迎指正):
问题一(较易):
sizeof的返回值类型是size_t,这是个无符号类型。当unsigned int 和int混合运算的时候,由于编译器认为unsigned int的表达长度比较长,它会认为b<=COUNTS-2两侧的值的类型都是以unsigned int的内存布局方式来存储的。等式右侧:counts-2结果类型被认为是unsigned int型的,5在内存中的表示为0x00000005.等式左侧:b的初值-1在内存中的存储为:0xFFFFFFFF,但由于它被认为采用了无符号方式存储,从而b<=COUNTS-2不满足。因此,循环不进入。
各位不难分析:为什么将 COUNTS -2先赋给一个int型的count变量,再将表达式改为b<=count就可以了!;
类似的问题:
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int b = 10;
const char * str = "adfasdfasdfad";
int a = (b - strlen(str) ) / 2;
printf("%d\n", a); //输出的a值不是一个负数,而是一个大正数,照着上面的思路很容易分析出正确的输出结果)
system("PAUSE");
return 0;
}
问题二(较易):
先弄清楚printf返回值的意思,摘自网上的一段英文解释:
Upon a successful return, the printf() function returns the number of characters
printed (not including the trailing '\0' used to end output to strings).
也即,printf返回的是打印的“字符”个数。
语句printf("%d\n",printf("%d",printf("%d",i)));中,
先执行的是printf("%d", i),它打出是43, 该printf的返回值是2(因为打印了'4'和’3'两个字符)
再执行printf("%d",printf("%d",i)),显然打印出2,该printf的返回值是1(因为打印了'1'这一个字符)
再执行最外层的printf,显然它输出的是1。
连起来,输出的是4321。
问题三(此题较易):
统计x的二进制表示中,'1'的个数。
问题四(此题较难):
为了清楚地解答此题,需要了解以下知识:1)浮点数在内存中的存储方式。2)内存的截断带来的问题。
第一个问题大家可以参考:《C语言与程序设计大学教程》一书或网上资料:http://blog.!
printf("%d\n", a);语句执行前,由于float型的a处在printf语句中,a的类型会自动提升为double型的。这不是我瞎扯的(When you pass a float as an argument to a variadic function (like printf()), it is promoted to a double,
which is twice as large as a float (at least on most platforms).)
根据上面的资料可以推算出12.5在计算机内部的存储格式为:
01000000 00101001 00000000 00000000 00000000 00000000 00000000 00000000,即0x41 48 00 00 00 00 00 00
在intel类型的机器上,采用的小端(little Endian)存储格式,即低字节在低地址存储。因此,0x41 48 00 00 00 00 00 00中的
后四个字节:00 00 00 00存储在低地址。当把0x41 48 00 00 00 00 00 00转换成int型输出时,由于int型数据占用四个字节,因此,只取低四个字节输出(发生了内存截断),而这四个字节里,存储的不就是00 00 00 00吗?因此,printf("%d\n", a);输出的是0!
再来看printf("%d\n", *(int *)&a);,这条语句的解释相对容易一些。
&a取出float型a的地址(此时由于是取地址,a的类型不会转换成double类型),该地址中存储的是12.5在内存中的二进制表示:01000000 00101001 00000000 00000000,(int*)&a把该地址转换成了int型数据的存储地址,*(int *)&a将该地址中的内容取出并转换成int型的值输出,而01000000 00101001 00000000 00000000的十进制数正好是1095237632!
问题五(较易):
指针的大小并不一定都是4!关于指针变量,有两个要点:1)它里面存储的是地址。2)该地址所代表的或说“捆绑”的内存单元是有大小区别的。
如:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[10];
printf("%d\n", sizeof(a));//输出40,a中存储了数组首地址,该地址”捆绑“了整个数组空间
printf("%d\n", sizeof(&a));//输出4,&a中存储了数组首地址,该地址”捆绑“了首元素的空间
printf("%d\n", sizeof(&a[0]));//输出4,&a[0]中存储了数组首地址,该地址”捆绑“了首元素的空间
system("PAUSE");
return 0;
}
言归正传:函数原型中 void size(int arr[SIZE])定义的形参,int arr[SIZE]虽然似乎指定了大小,但实际上,数组arr是个不完整数据类型,从而sizeof(arr)的输出为4!
以下代码即可以说明arr是个不完整的数据类型:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
void size(int arr[SIZE])
//等价于void size(int arr[])
{
printf("size of array is:%d\n",sizeof(arr));
}
int main()
{
int arr[
100];
size(arr); //实际参数有100个元素,而形参只指定了10个,显然只有当形参是不完整数据类型时,编译才不会报错!
system("PAUSE");
return 0;
}