2019-05-19 C 基础回顾(1)

C 基础回顾

1.读程序求输出

#include<stdio.h>
int i = 2;
int main(){
    int i = i;
    printf("%d\n",i);
}

编译可以通过,不过会有警告,因为

int i = i 企图使用自己初始化自己,用一个未初始化的去初始化自己,没用。

2. 读取程序求输出

#include<stdio.h>
int func(int x){
    int cnt = 0;
    while(x){
        ++cnt;
        x = x & (x - 1);
    }
    return cnt;
}
int main(){
    printf("%d\n",func(9999));
    return 0;
}

x & x - 1 :干啥了呢?

去掉了最后一位的1

x & (-x) =》lowbit(x)的意思是将 x 转化成二进制数之后,只保留最低位的1及其后面的0,截断前面的内容,然后再转成10进制数。

3 . 用位运算实现两个整数的加法运算。

  1. 递归
int getSum(int a, int b){
    return a == 0 ? b : getSum((unsigned)(a & b) << 1,a ^ b);
}
  1. 迭代
int getSum(int a, int b){
    while(a){
        b = a ^ b;
        a = (unsigned)(a & (b ^ a)) << 1;
    }
    return b;
}

​ a ^ b : 无进位的相加 ,

​ a & b : 每一位的进位 ,

补充:

​ (a & b) + (a ^ b) << 1,求的是(a + b)/ 2 ,注意的是unsigned 来处理负数。所以说1+-2也是可以的,因为-2 是用补码的形式在内存中存储的,所以说可以和正数的相加一起处理。

补充:

​ -b = ~b+1

​ 所以a - b => return getSum(a,getSum(~b,1));

4.以下程序输出是啥

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <conio.h>
using namespace std;
int main() {
    float a = 1.0f;
    cout << (int)a << endl;
    cout << &a << endl;
    cout << (int &)a << endl;
    cout << boolalpha << ((int)a == (int&)a) << endl; ??
    float b = 0.0f;
    cout << (int)b << endl;
    cout << &b << endl;
    cout << (int &)b << endl;
    cout << boolalpha << ((int)b == (int&)b) << endl; ??
    return 0;
}

推荐阅读:

强制类型转换(int)、(int&)和(int*)的区别

(int)x 强制类型转换,是将浮点数x为参数构造整数(即float转换为int)

(int &)y 则是告诉编译器将y看成int对待(内存里的数据不做任何转换),所以(int &)x值为1071 644 672。
至于(int*)的话,我就不多说啦,就是强制转换成整型指针,一般人们容易混淆的是(int)和(int&)这两个。

补充:浮点数0.0是比较特殊的,它并不按照上面说的浮点数的格式存储,浮点数0.0在内存里的存储是000.....000(全零)。

5. 以下这段程序的输出是啥?

#include<stdio.h>
int main(){
    unsigned int a = 0xFFFFFFF7;
    unsigned char c = (unsigned char)a;
    char *b = (char *)&a;
    printf("%08x,%08x\n",c,*b);
    return 0;
}
  1. 大小端 推荐阅读  详解大端模式和小端模式

    举一个例子,比如数字0x12 34 56 78在内存中的表示形式。

1)大端模式:Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。(其实大端模式才是我们直观上认为的模式,和字符串存储的模式差类似)

低地址 --------------------> 高地址
0x12 | 0x34 | 0x56 | 0x78

2)小端模式:Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

低地址 --------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12

可以编写一个小的测试程序来判断机器的字节序:

BOOL IsBigEndian()  
{  
    int a = 0x1234;  
    char b =  *(char *)&a;  //通过将int强制类型转换成char单字节,通过判断起始存储位置。即等于 取b等于a的低地址部分  
    if( b == 0x12)  
    {  
        return TRUE;  
    }  
    return FALSE;  
}

联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写:

BOOL IsBigEndian()  
{  
    union NUM  
    {  
        int a;  
        char b;  
    }num;  
    num.a = 0x1234;  
    if( num.b == 0x12 )  
    {  
        return TRUE;  
    }  
    return FALSE;  
}
  1. 整数提示 推荐阅读 整数提升

​ C99标准中有明确提到整数提升的概念:"如果int能够表示原始类型中的所有数值,那么这个数值就被转成int型,否则,它被转成unsigned int型。这种规则被称为整型提升。所有其它类型都不会被整型提升改变。"

​ 为什么会有整数提升?这是因为对于int类型数据作运算时,CPU运算速度是最快的,所以C语言会对数据作整数提升的处理,使得程序的运行速度尽可能地快

比如下面的这个例子:

int main()
{
   char a=127;
   unsigned char b=255;
   short c=32767;
   unsigned short d=65535;
 
   printf("char: a+1=%d %d\n",a+1,sizeof(a+1));
   printf("uchar: b+1=%d %d\n",b+1,sizeof(b+1));
   printf("short: c+1=%d %d\n",c+1,sizeof(c+1));
   printf("ushort: d+1=%d %d\n",d+1,sizeof(d+1));
 
   return 0;
}
 
结果:
char: a+1=128 4
uchar: b+1=256 4
short: c+1=32768 4
ushort: d+1=65536 4

针对源题目

  1. 在小端的机器上c = 0xF7;大端就是0xFF
  2. b 存在整数提升,又因为是负数,所以自动补1结果就是0xFFFFFFF7

6. 以下程序输出结果是

#include<stdio.h>
int main(){
    unsigned char a = 0xA5;
    unsigned char b = ~a>>4+1;
    printf("%d\n",b);
    return 0;
}

这个就是上述的整数提升过程,~a >> 5

5 是int 所以会将~a 提升到int 4 字节

然后截取1字节赋值给b。

7.不用”if“,”?:“,”switch“或其他判断语句,求两个数中较大的数或较小的数

int Find1(int a, int b) {
    return ((a + b) + abs(a - b)) / 2;
    //return ((a + b) - abs(a - b)) / 2;
}
 
/*
当a大于b时,a-b为正,右移sizeof(int) * 8 - 1后,最右侧一位为0,0^1 = 0;
当a小于b时,a-b为负,右移后最右侧一位为1,1^1 = 1
*/
int Find2(int a, int b) {
    int c[2] = {a, b};
    int z = a - b;
    z = (z >> (sizeof(int) * 8 - 1)) & 1;
    return c[z];
    /*
    int c[2] = {b, a};
    int z = a - b;
    z = (z >> (sizeof(int) * 8 - 1)) & 1;
    return c[z];
    */
}
 
int Find22(int a, int b) {
    int flag = ((a - b) >> (sizeof(int) * 8 - 1)) & 1;
    return (a - (a - b) * flag);
    //return (b - (b - a) * flag);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容