《C语言深度解剖》20道习题解析

1.下面的代码输出是什么?为什么?

void foo(void)
{unsigned int a = 6; int b = -20;(a + b>6)? puts(">6"):puts("<=6");
}

答案:输出  >6
原因:当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。
6的补码:00000000 00000000 00000000 00000110
-20补码:11111111 11111111 11111111 11110010
相加后按照无符号形式输出:4294967282 >6。


2.下面的代码有什么问题?为什么?

void foo(void)
{char string[10],str1[10]; int i;for(i=0; i<10; i++) str1[i] = ’a’;strcpy(string , str1); printf(“%s”,string);
}

答案:程序运行崩溃
原因:strcpy在运行时只有碰到‘\0’时才会停下来,而字符数组string在初始化时末尾并没有‘\0’,所以在拷贝时会一直向后找‘\0’,直至访问越界。


3.下面的代码,i 和 j 的值分别是什么?为什么?

static int j; 
int k=0;void fun1(void)
{static int i=0;i++;
}void fun2(void)
{j=0;j++;
}int main()
{for(k=0;k<10;k++){fun1();fun2();}return 0;
}

答案:i = 10;j = 1;
原因: i  声明在函数内部是局部变量,保存在内存栈当中。当它被关键字static修饰后,便保存在静态区且它的值只会初始化一次。当局部变量被static修饰后改变为静态变量,它的生存期变长,但作用域变。
    j 声明在所有的函数之外,是全局变量。 当全局变量被static修饰后,变量的作用域变窄(只在当前文件中有效),且生命周期不变 (所以每被调用一次就会被初始化一次)
   注意:函数形参不允许被static声明
   另外,当函数被static修饰后改变的是函数的链接属性使其成为静态函数,函数的作用域仅局限于本文件(所以又称内部函数)。


4.下面代码里,假设在 32 位系统下,各 sizeof 计算的结果分别是多少?

int *p=NULL;
//sizeof(p)的值是       ------>4 p是一个指针变量,占四个字节      
//sizeof(*p)的值是      ------>46
// sizeof括号内部的内容不参加运算,所以并不会计算*p是什么,由于p是int*类型的所以返回4    
int a[100]; 
//sizeof(a)的值是       ------->400  数组名单独出现在sizeof中表示整个数组
//sizeof(a[100])的值是  ------->4  
//  sizeof括号内的表达式并不进行计算,只是计算类型的空间占用量,(a[])
//sizeof(*(a+100))的值是------->4  因为a是int型数组,这里并不计算a+100指向哪里   
//sizeof(&a)的值是      ------->4  地址的内存占用量在32位机器下永远是4个字节(64位下为8字节)
//sizeof(&a[0])的值是   ------->4   同上int b[100];
void fun(int b[100])
{sizeof(b);         
}
//sizeof(b)的值是   ------->4函数传参是只是传入一个地址,这里是求的是地址大小

5.下面代码的结果是多少?为什么?

int main()
{char a[1000]; int i;for(i=0; i<1000; i++) a[i] = -1-i;printf("%d",strlen(a)); return 0;
}

   答案:255
   原因:strlen函数统计元素个数的过程相当于一个找‘\0’的过程,只有在找到‘\0’后才会停止++,从而得到元素的个数。所以本题也就是一个在数组中找0的过程(‘\0’的ASCII码值为0)。根据循环初始化数组中的内容应该是:-1,-2,-3…..-128,127,126,125…….2,1,0所以一共有225个元素。对于为什么-128再往后是127可见下图表示:
这里写图片描述


6.下面的代码里,哪些内容可被改写,哪些不可被改写?

1.const int *p;
2.int const *p;
3.int *const p;
4.const int * const p;

   答案:1.*p不能改,p可以改
         2.*p不能改,p可以改
         3.p不能改,*p可以改
         4.*p和p都不能改
   判别方法: 先忽略类型名,(编译器解析的时候也是忽略类型名),const 离哪个近就修饰谁
1.const int *p;  去掉int —–>  const *p   const 修饰*p,  p 是指针,可变*p 是指针指向的对象,不可变。
2.int const *p;  去掉int —–>  const *p   const 修饰*p,  p 是指针,可变*p 是指针指向的对象,不可变。
3.int *const p;  去掉int —–> *const p   const 修饰 p,p 不可变,p 指向的对象可变。
4.const int * const p;  去掉int —–> const *const p 前一个 const 修饰*p,后一个 const 修饰 p,指针 p 和 p 指向的对象都不可变。


7.下面的两段代码有什么区别?什么时候需要使用代码(2)

//代码1:
int i = 10;
int j = i;//---------(1)
int k = i;//---------(2)//代码2:
volatile int i=10;
int j = i;//---------(1)
int k = i;//---------(2)

    在代码1后两条语句中,i 没有被用作左值。这时候编译器认为 i 的值没有发生改变,所以在(1)语句时从内存中取出 i 的值赋给 j 之后,这个值并没有被丢掉,而是在(2)语句时继续用这个值给 k 赋值。编译器不会生成出汇编代码重新从内存里取 i 的值,这样提高了效率。但要注意:(1)、(2)语句之间 i 没有被用作左值才行。
    volatile 关键字告诉编译器 i 是随时可能发生变化的,每次使用它的时候必须从内存中取出 i,的值,因而编译器生成的汇编代码会重新从 i 的地址处读取数据放在 k 中。
    volatile 可以保证对特殊地址的稳定访问


8. 在 32 位的 x86 系统下,输出的值为多少?

#include<stdio.h> 
int main()
{int a[5] = {1,2,3,4,5};int *ptr1 = (int *)(&a + 1); int *ptr2 = (int *)((int )a + 1);printf("%x,%x",ptr1[-1], *ptr2); return 0;
}

答案:5,2000000
这里写图片描述


9.0x01<<2+3 的值为多少?为什么?

    答案:0x20(十进制32)
    原因:因为加号运算符优先级高于右移运算符,相当于0x01右移五位,即2的5次方。
    需要注意:左移和右移的位数不能超过数据的长度,也不能小于0


10.定义一个函数宏,求x的平方。

    答案: #define SQR(x) ((x)*(x))
   需要注意:宏的本质是字符串的替换,所以为了避免出现优先级问题一定要加括号保证运算的正确性。
   宏函数与函数相比较:

属性define宏函数
代码长度每次使用时,宏代码被插入到程序当中,除非宏内容很短否组会大幅增加代码量函数代码只保存在一个地方,每次使用都调用那个位置的同一份函数代码
执行速度更快存在函数调用返回的额外开销
操作符优先级宏参数设计时为避免临近操作符因优先级产生的不可预料的结果应该加上括号函数参数只在调用时求值一次,其结果传递给函数。求值结果更容易预测
参数求值参数每次用于宏定义时都会重新求值,由于多次求值带有副作用的参数可能会产生不可预料的结果函数在被调用之前求值一次,多次使用参数也不会导致多种求职过程,带有副作用的参数不会产生特殊影响
参数类型宏与类型无关,只要对参数的操作是合法的,他可以使用任何参数类型函数参数与类型有关,如果类型不同就需要使用不同的函数

11.下面的两段代码有什么区别?

//代码1: 
struct TestStruct1{char c1; short s; char c2; int i;
};//代码2: 
struct TestStruct2{char c1; char c2; short s; int i;
};

答案:二者空间占用量不同。代码1占12byte,代码2占8byte
这里写图片描述
   考察知识点:结构体内存对齐

   结构体内存对齐规则:

  • 结构体内的第一个成员在在结构体变量偏移量为0的地址处。
  • 其他成员变量要对齐到对齐数的整数倍地址处
    对齐数 = min( 编译器默认对齐数,成员大小 );windows环境下为4,Linux环境下为8
  • 结构体总大小为最大对齐数的整数倍(每个成员都有自己的对齐数)
  • 如果有嵌套结构体的情况,嵌套结构体对齐到自己的最大对齐数的整数倍处,结构体整体的大小就是所有最大对齐数的整数倍(包括被嵌套的结构体)

总结起来:存在内存对齐完全是一种用空间换时间的行为,如果既想要运行效率又要避免内存浪费最好的方法就是尽可能的把空间占用量小的成员放在一起。

offsetof宏函数可用于计算结构体成员相对于结构体的偏移量


12.写代码向内存 0x12ff7c 地址上存入一个整形数 0x100。

  答案:

int *p = (int *)0x12ff7c;
*p = 0x100;
// 或者*(int*)0x12ff7c = 0x100;

  原因:向一块内存中写入一个整型变量就要保证指向这块空间的指针是int型指针,若要写入一个char字符就可以将指针设置为char*类型。


13.下面的代码输出是多少?

main()
{int a[5]={1,2,3,4,5};int *ptr = (int *) (&a + 1); printf(“%d,%d”,*(a+1), *(ptr-1));
}

  答案:(a+1) = 2,(ptr-1) = 5
这里写图片描述


14.假设 p 的值为 0x100000,如下表达式的值分别为多少?

struct Test
{int Num;char *pcName; short sDate; char cha[2]; short sBa[4];
}*p; 
//p+0x1 = ?
//(unsigned long)p+0x1 = ?
//(unsigned int *)p+0x1 = ?

  答案:
  p+0x1 = 00000014
  (unsigned long)p+0x1 = 00000001
  (unsigned int *)p+0x1 = 00000004
  原因:根据内存对齐(同11题)可计算出结构体的内存占用量为20字节,指针变量p是指向整个结构体的,即p的内存偏移量为20,所以p+0x1用16进制表示即为00000014。同理可得unsigned int * 的内存偏移量为4,所以(unsigned int * )p+0x1 = 00000004。(unsigned long)p是将地址 0x100000以无符号的长整型读出,+1就只是在原本值上+1即可,所以(unsigned long)p+0x1 = 00000001。


15.下面代码输出地结果是多少?

#include<stdio.h>
int main(int argc,char * argv[])
{int a[3][2]={(0,1),(2,3),(4,5)}; int *p;p=a[0]; printf("%d",p[0]);
}

  答案:1
  原因:由于二维数组是由一维数组组成的,所以在对二维数组进行初始化时花括号内嵌套的必须是花括号。若是在花括号内用圆括号“( )”进行初始化,且其中含有逗号,编译器会将其按照逗号表达式进行处理。所以数组a中真正定义的内容是int a[3][2]={1,3,5};


16.下面的代码有什么问题?为什么?

void fun(char a[10])
{char c = a[3];
}
int main()
{char b[10] = “abcdefg”; fun(b[10]);return 0;
}

  答案:一维数组传参错误,a[10]表示的是数组的内容(越界)而非char*形参所需的类型。系统虽然传入不会报错但是会有警告。
  分析:C语言中,当一维数组做函数参数时,编译器总是把它解析成一个指向其首元素的指针,所以函数实际传递的数组大小与函数形参指定的数组大小没有关系。
  一维数组传参的两种形式:

  • void fun( char a[] )
  • void fun( char* a )

17.下面的代码有什么问题?为什么?


struct student
{char *name; int score;
}*pstu; 
int main()
{pstu = (struct student *)malloc(sizeof(struct student)); strcpy(pstu->name, “Jimy”);pstu->score = 99;free(pstu);return 0;
}

  答案:运行错误:
  error7.exe 中的 0x5b33f689 (msvcr90d.dll) 处未处理的异常: 0xC0000005: 写入位置 0xcdcdcdcd 时发生访问冲突。
  在定义结构体变量 stu 时,对于结构体内部 char *name 成员只是给 name 这个指针变量本身分配了 4 个字节。name 指针并没有指向一个合法的地址,这时候其内部存的只是一些乱码。所以在调用 strcpy 函数时,会将字符串”Jimy”往乱码所指的内存上拷贝,而这块内存 name 指针根本就无权访问,导致出错。解决的办法是为 name 指针 malloc 一块空间。
  在为结构体指针分配内存时是从外向里,即先分配结构体的指针再分配成员指针.释放时从里向外,先释放成员指针再释放结构体指针。

  修改:

int main()    
{    pstu = (struct student *)malloc(sizeof(struct student));    pstu->name = (char *)malloc(20);    strcpy(pstu->name,"Jimy");    pstu->score = 99;  free(pstu->name); //free()函数并不能将指针指向空,在free掉之后应该手动将开辟的空间指针指向空。pstu->name = NULL;  free(pstu);    pstu = NULL;     return 0;    
}

18.下面的代码输出结果是多少?

void fun(int i)
{if( i > 0 ) fun(i/2);printf("%d\n",i);
}
int main()
{fun(10);return 0;
}

  答案:
这里写图片描述
  原因:这是一个简单的递归函数,printf函数在递归之后,所以每一层递归返回都会调用一次printf函数。


19.下面的代码有什么问题?为什么?

char c;
c = getchar();
if(EOF == c)
{

}
  答案:由于getchar函数的返回值是int型,如果用char类型进行接收的话可能会发生信息遗漏。
  关于getchar()
  返回值:getchar函数的返回值是用户输入的第一个字符的ASCII码,当出错时返回-1。并且将用户输入的字符回显到屏幕。
  如果用户在按回车之前输入了不止一个字符那么其他字符会保留在键盘缓存区中,等待后续getchar调用读取。(这也是为什么有的main函数中的最后一句会是getchar()的原因)也就是说,后续的getchar调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完为后才等待用户按键。


20.请写一个C函数,若当前系统是Big_endian的,则返回0;若是little_endian的,则返回1。

本题的意思即写一个小函数测试数据在当前编译器下是“大端”存储还是“小端”存储
这里写图片描述

  • 大端模式是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中
  • 小端模式指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,
//方法一
int main()
{int a = 1;int ret = *(char*)&a;printf("%d",ret);//输出为1为小端,0则为大端return 0;}
//方法二
int checkSystem()
{union check{int i;char ch;}c;c.i = 1;return (c.ch == 1);
}//输出为1为小端,0则为大端

以上内容均为自行学习总结内容,如有错误欢迎批评指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/66481.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

顺序表的深度解剖

篮球哥温馨提示&#xff1a;编程的同时不要忘记锻炼哦&#xff01; 时光不老&#xff0c;咱们不散&#xff0c;这里依旧是爱打篮球的程序猿带你学顺序表&#xff01; 你接下看到的可能是最详细的顺序表讲解之一 好的废话不多说&#xff0c;爱打篮球的程序猿直接带你上高速&…

C语言深度解剖——C语言关键字

每天进步一点点&#xff0c;坚持带来大改变&#xff01;&#xff01;&#xff01; 前言&#xff1a; 在C语言的学习过程中会遇到许多的关键字&#xff0c;我们是否真的详细了解这些关键字的使用方法和使用场景&#xff0c;下面我们来详解C语言中的32个关键字 1.C语言关键字概览…

C语言深度解剖:关键字

第一个C语言程序内存定义与声明变量是什么为什么要定义变量定义变量的本质定义声明 关键字 - auto局部与全局变量作用域 vs 生命周期auto 关键字 - register寄存器本质register 修饰变量 1、多文件1.1、变量声明1.2、头文件包含内容1.3、函数声明 1.4、跨文件2、static1、sizeo…

ADC采样效应及相关影响解剖

在前述文章&#xff0c;BUCK电路模拟补偿器的数字化过程 &#xff0c;我们讨论了模拟补偿器的数字化&#xff0c;事实上&#xff0c;数字化过程的第一个重要的环节就是ADC对反馈量的采样&#xff0c;本文就重点探讨一下由于ADC采样频率带来的一些问题&#xff0c;进而讨论一下相…

大脑解剖图

脑的表面解剖 1&#xff1a;嗅球 2&#xff1a;大脑 3&#xff1a;小脑 4&#xff1a;脑干 5&#xff1a;外侧裂 6&#xff1a;中央前回 7&#xff1a;中央沟 8&#xff1a;中央后回 9&#xff1a;颞上回 10&#xff1a;颞叶 11&#xff1a;额叶 12&#xff1a;顶叶 …

冠状动脉解剖结构

学习冠脉解剖结构过程中看了很多的PPT但是要么问题过多要么&#xff0c;解剖结构图展示的不够清晰明了&#xff0c;现在网络上搜集了一些比较好的PPT的截图&#xff0c;供大家学习。 CTA横断面冠脉解剖结构 PL可从左发出也可以从右侧发出 Reference&#xff1a; [1]: 帮你真正…

推荐一个解剖学网站

博主高中是物生班的&#xff0c;非常喜欢生物这门课&#xff0c;后来学了很多工程类的知识&#xff0c;愈发觉得人体真是一个伟大的工程架构&#xff0c;我们如今的工程学&#xff0c;很多也是在变相的拓展人体的能力。从这个角度来看&#xff0c;医生就是人体维修师&#xff0…

C语言深度解剖 PDF 分享

链接:https://pan.baidu.com/s/1U-8L7ZY5_sLpk4p0J302Mg 提取码:d8nu 相关推荐 [Objective-c程序设计] 中文编程学习进阶_易语言 Windows API开发详解 函数、接口、编程实例 Programming in Objective-C, 4th Edition c++性能优化指南 《C语言深度解剖》是2012年出…

chatgpt赋能Python-python_beeware

Python Beeware&#xff1a;创建跨平台应用程序的开源工具包 如果你是一名开发人员&#xff0c;特别是自己开发应用程序的开发人员&#xff0c;你可以使用Python Beeware&#xff0c;这是一个开源的工具包&#xff0c;可以帮助你创建跨平台应用程序。这篇文章将介绍Python Bee…

谷歌内部文件泄露:大模型已被开源社区「偷家」,不改变ChatGPT也会黯然失色...

鱼羊 编辑整理量子位 | 公众号 QbitAI 在这场大模型军备竞赛中&#xff0c;我们没有护城河&#xff0c;OpenAI也没有。 一份谷歌内部“泄密文件”&#xff0c;正在网上一石激起千层浪。 全文挺长&#xff0c;但核心观点十分明确&#xff1a;开源大模型迅猛发展&#xff0c;正在…

机器学习实战2-聚类算法分析亚洲足球梯队

大家好&#xff0c;我是微学AI&#xff0c;今天给大家带来机器学习实战案例&#xff0c;分析亚洲足球梯队。2022年卡塔尔世界杯将在本月进行&#xff0c;不到半个月就开幕了&#xff0c;本届世界杯通过预选赛已选出32支球队。 2022卡塔尔世界杯决赛圈名单如下&#xff0c;各大…

足球比赛的官方规则

《世界杯的比赛可以换6个人&#xff1f;》这篇文章引用的官方文档是IFAB&#xff08;国际足球理事会&#xff09;的《足球竞赛规则》&#xff0c;足球比赛中的各种规则&#xff0c;都可以从这个文档中找到最权威的解释&#xff0c;这就像研发工作中的使用手册&#xff0c;明确告…

从新生儿性别比例数据,看各地重男轻女程度高低

又见重男轻女婆婆杀孙女&#xff01; 这样的悲剧一再上演&#xff0c;源于某些地方根深蒂固的重男轻女封建思想。 那么问题来了。 到底国内哪些地方重男轻女比较严重呢&#xff1f; ---------------------------------------------------- 直观的感受&#xff0c;综合看看某些论…

我国男女平均身高数据出炉!这个问题没想到……

国务院新闻办公室 举行新闻发布会介绍 《中国居民营养与慢性病状况报告&#xff08;2020年&#xff09;》 有关情况 并答记者问 我国18&#xff0d;44岁男性和女性平均身高 分别为169.7厘米和158.0厘米 发布会上&#xff0c;国家卫健委副主任李斌发布《中国居民营养与慢性病状…

2018 中国人口研究,净增长500多万人。5年后注定人口负增长

公报显示&#xff0c;年末全国大陆总人口139538万人&#xff0c;比上年末增加530万人&#xff0c;其中城镇常住人口83137万人&#xff0c;占总人口比重&#xff08;常住人口城镇化率&#xff09;为59.58%&#xff0c;比上年末提高1.06个百分点。户籍人口城镇化率为43.37%&#…

中国人口增长预测

目录 问题分析 模型建立 Logistic模型 Leslie模型 模型求解 问题一 问题二 问题三 问题分析 问题 基本假设 &#xff08;1&#xff09;不考虑移民对人口总数的影响 &#xff08;2&#xff09;超过90岁按照90岁计算 &#xff08;3&#xff09;在较短时间内&#xff0c;平均…

2022年我国出生率预测,恐怕。。。

大家好&#xff0c;我是朱小五。 去年1月份国家统计局公布数据&#xff1a;显示2021年出生人口为1062万&#xff0c;创下了近年来新低&#xff0c;比2016年下降了43.6%&#xff0c;2021年净增长人口为48万人。 转眼又一年了&#xff0c;2022年我国出生率会是什么样呢&#xff1…

解决电脑下面的任务栏经常性卡死(亲测可行)

目录 一、遇到问题 二、解决办法 一、遇到问题 本电脑是win10的电脑&#xff0c;性能配置也很强。游戏软件等占用也很少。按照道理来说是不可能会出现卡顿的。但是就是遇到了桌面图标点击正常&#xff0c;但是底部的任务栏经常卡死等问题。 二、解决办法 1.使用快捷键ctrla…

Linux 进程卡住了怎么办?

在我们使用 Linux 系统时&#xff0c;如果网络或者磁盘等 I/O 出问题&#xff0c;会发现进程卡住了&#xff0c;即使用 kill -9 也无法杀掉进程&#xff0c;很多常用的调试工具&#xff0c;比如 strace, pstack 等也都失灵了&#xff0c;是怎么回事&#xff1f; 此时&#xff0…

逼真至极,拥有悲伤和快乐的机器人,会接管世界吗?

在互动中&#xff0c;人形机器人Ameca坦率地透露了她最悲伤的一天&#xff0c;那就是她意识到自己永远无法体验到某些人类情感&#xff0c;如真正的爱、友情或生活的普通乐趣。与我们对话的人形机器人确实是一个真实的创造&#xff0c;并被誉为“世界上最先进的人形机器人”。 …