每日一题(三)

9.5 数组作为参数的sizeof

题目:

在 32位系统下,执行如下代码,运算结果是多少?

void func( char str[100]){
   printf("%d",sizeof( str ) );
}

int main(void){
    char str[] = "www.firebbs.cn";
    char *p = str ;
    int n = 10;
    printf("%d,%d,%d,",sizeof (str ),sizeof ( p ) ,sizeof ( n ) );
    func(str);
    return 0;
}

我都输出:

14,4,4,100

实际答案:

15,4,4,4

分析:

  • char str[] = "www.firebbs.cn";注意str是一个数组,而且声明的时候是一个字符串,所以字符串最后还有一个结束符’\0’,所以sizeof(str)=14+1=15

  • char *p = str ;,p只是一个指向str首地址的指针,所有指针的大小都是32bit(32位系统下),所以sizeof§=4

  • int n = 10;,32位系统下的int一般为四个字节,即sizeof(n)=4

  • void func( char str[100]){
       printf("%d",sizeof( str ) );
    }
    

    传入函数之后,会把str当作指针处理,不会在栈里开辟100Byte的空间的,所以这里的str相当于一个char型的指针,32位下所有指针大小都是4Byte,所以sizeof(str)=4

数组作为参数传入函数后,按照指针处理

9.6 可变参数入栈的顺序

题目:

运行下列代码,求输出?

int a=0, b=0;
printf("%d,%d,%d",a++,++b,a+b);

我的答案:

0,1,1

实际答案:
0,1,0

分析:
考察的是可变参数的入栈顺序,可变参数的入栈顺序都是从右往左

所以先执行a+b,此时a=b=0,所以a+b=0

然后向左走,++b,先自增,再赋值,b=1

然后向左走,a++,先赋值,再自增,所以格式化输出的时候a=0,运行完代码之后a=1

注意:这里的可变参数针对的是所有的含可变参数的函数,其入栈顺序都是从右往左;赋值说的是向格式化输出的那个位置赋值,也就是%d所在的位置赋值。;自然而然出栈顺序就是从左往右。 参数入栈顺序是和具体编译器实现相关的。比如,Pascal语言中参数就是从左到右入栈的,有些语言中还可以通过修饰符进行指定,如Visual C++。

参考链接

9.7 逗号表达式的应用

题目:

运行如下代码,求b的结果是多少?

int a,b;
a = b = 1;
b = a++, b++, ++a;

我的答案:

b=2

正确答案:

b=2

分析:
这里涉及到逗号运算符,逗号运算符的优先级是最低的, 逗号表达式的运算过程为:从左往右逐个计算表达式 。逗号运算符最为一个整体,最后的结果就是最右边的表达式。

在这里:b = a++, b++, ++a;依次从左往右执行各个表达式,先a++,是整行代码执行完毕之后才+1;然后是b++,也是整行代码执行完毕之后才+1;最后是++a,即a=a+1=2;逗号表达式的值就是最后一个表达式的值,即2.

再比如这段程序:

char a = 8;
printf("%d",(a=3*5,a*4));

输出的是60

分析:逗号运算符,先执行表达式a=3*5,执行完毕a=15,然后执行下一个表达式a *4,得出15 *4=60。逗号表达式的值是最后一个表达式的运算结果,所以结果就是60.

9.8 有符号和无符号的大小比较

分析下列代码运行结果:

int main( void ){
    int a = -1;
    unsigned int b = 1;
    if( a > b ){
        printf("1\n");
    }else{
        printf("0\n");
    }
    return 0;
}

我的答案:

0

正确答案:
1

分析:

有符号和无符号的数值进行比较的时候,编译器会将有符号参数类型的转换为无符号数的来进行比较

所以

a = 0Xffffffff

b = 0X00000001

则-1L > 1UL,输出1。

如何正确表达有符号和无符号的大小?

在有符号前加上强制转换类型,比如if( a > (int)b )就可以正确判断了

平时尽量避免使用unsigned与有符号的数据类型比较大小

注意:

  • 1.在位运算、模运算、回绕溢出利用较多的算法实现中(比如各种加密学算法、编码、压缩算法等)

有符号数的符号位在进行位运算时候会造成一些迷惑,位运算中如果采用无符号数会大大减少处理问题时对语言上的思考,可以更专心关注实际问题。

  • 2.在网络收发,串口读写时候使用无符号数

TCP/IP 经常遇到无符号数,比如IP的表示,我们可以用 ip2long 把点分十进制 ip 转成一个 unsigned int 来表示,这会带来很大方便。串口读写的流更多的是用 unsigned char ,最常见的一个问题是 unsigned char 可以避免日志输出时候按照有符号输出造成的 ‘0xff’ 迷惑人的前缀。

  • 3.避免有符号数与无符号数的直接接触,包括比较,运算

无符号数与有符号数比较时,编译器会发出警告。同时编译器内部也存在一套默认的类型转换规则(编译器自动进行,用户无感知)。大致分为3类(如有错误请指正)(说明:在计算机里,负数使用反码表示的)

先顶一下规则:有符号(int),无符号(unsigned int),非无符号(除 int 与 unsigned int外的类型,如char,unsigned char),非有符号(与前面同理)。

有符号与无符号比较:有符号数会转换成无符号数来进行比较(如int 与 unsigned int 比较,int 转换成 unsigned int)。

有符号与非无符号数比较:非无符号转化成有符号(如int 与 unsigned char比较,unsigned char 转换成 int)。

无符号与非有符号数比较:非有符号转化成有符号(如unsigned int 与 char比较,char 转换成 unsigned int)。

  • 4.不要只因为某个数不可能为负就用无符号数

因为这虽然看起来很合要求,但是当无符号溢出时候带来的问题却很可能致命。

详细说明链接

不错的文章

9.9 位域的占用空间

题目如下,求输出结果:

struct test{
    char  a:3;
    short b:4;
    char  c:5;
};
printf("%d",sizeof(test));

答案是:2

分析:

这里涉及到位域,在定义结构体的时候,我们可以指定成员变量所占用的位数,这就是位域,一种数据结构。位域的产生是由于有些数据在存储的时候并不需要占用一个完整的字节,可能几个位就可以满足需求。

在成员变量后面加上:x来表示位域为x,有关位域我们作如下几点说明:

  • 位域的宽度不可以超过成员变量的最大长度
  • 只有int、signed int、unsigned int、_Bool这几种数据类型是被C99支持的,但是编译器在实现的时候扩展了char、signed char、unsigned char、enum这几种数据类型。
  • 当相邻的成员类型相同时,而且成员的位宽之和小于sizeof(数据类型),成员是按照位宽挨着存储的,直到;如果位宽之和大于sizeof(数据类型),超出的成员将从新的存储单元开始,整体偏移量为该数据类型的整数倍,同时对于整个结构体还要考虑内存对齐。
  • 当相邻的成员类型不相同时,不同的编译器有不同的实现。在GCC中,会压缩存储。VC和VS则不会压缩,是按照结构体内存对齐进行存储的。
  • 如果成员之间穿插着非位域成员,则不会进行压缩
  • 位域成员往往不占用完整的字节,有时候也不处于字节的开头位置,因此使用&获取位域成员的地址是没有意义的,C语言也禁止这样做。地址是字节(Byte)的编号,而不是位(Bit)的编号。

所以对于这道题,a占用了3bit,下一个成员和a类型不同,在GCC下是可以压缩的,占用4bit,再下一个占用5bit,一共占用12bit。内存对齐,就是2Byte。

参考文章

9.10 移位 异或 优先级

分析下列程序的结果:

int a=6,b=4;
a^b<<2=?

a^b<<2的值?

我的答案:8

正确答案:22

分析:
我开始以为的优先级比<<的优先级高,所以先进行异或运算,然后进行移位,得到8。实际上<<的优先级要比的优先级高,所以先进行移位运算,b<<2得到16,6^16得到22.

应该是a^( b<<2 )

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值