C语言集训-陈朝旭-第二次作业

322 阅读22分钟

一.C编程预备计算机专业知识

1.CPU、内存条、显卡、主板、显示器之间的关系

graph TD
硬盘中的程序 --被执行---调入--> 内存条
CPU --处理--> 内存条
主板 --- 内存条
主板 --- 显卡
主板 --- 声卡
主板 --- CPU
内存条 --> 视频 ---显卡--> 显示器
内存条 --> 声音 ---声卡--> 音响

2.HelloWorld程序是如何运行起来的

graph TD
代码文件 --执行----vscode生成---> 后缀名为.exe的文件 --vscode请求操作程序执行生成的后缀名为.exe的文件 --> 操作系统 -- 调用CPU --> 运行.exe文件

3.数据类型

graph TD
数据类型 --- 基本类型数据
数据类型 --- 复合类型数据
基本类型数据 --- 整数
基本类型数据 --- 浮点数/实数
基本类型数据 --- 字符
整数 --- 整型/int ---4字节
整数 --- 长整型/shortint ---8字节
整数 --- 短整型/longint ---2字节
浮点数/实数 --- 单精度浮点数/float ---范围相对较小占4个字节 ---考虑数据一定时内存占量是否浪费
浮点数/实数 ---双精度浮点数/double ---范围相对较大占8个字节 ---考虑数据一定时内存占量是否浪费
字符 ---单个字符 ---char ---占1个字节
字符 ---字符串
复合类型数据 --- 结构体
复合类型数据 --- 枚举
复合类型数据 --- 共用体

4.什么是变量

变量的本质就是内存中一段存储空间,是一个有名字的具有特定属性的存储单元 1、程序在多次运行时,每次运行时变量分配的物理内存地址都不同

2、在具体到程序某一次的完整运行过程中时,变量的物理内存地址是固定不变的

3、由于在程序运行过程中变量的物理内存地址固定不变,变量又和物理内存对应,故我们可以将变量理解为是一个物理内存地址的常量。

以上三点源自bilibili弹幕

5.CPU、内存条、VC++6.0、操作系统之间的关系

graph TD
VC++6.0软件 --请求--> 操作系统 ---内存条 --分配-->一块空闲的空间
程序中的变量 --关联---一块空闲的空间
CPU --处理-->内存条
CPU --处理-->一块空闲的空间


6.变量为什么必须得初始化

初始化就是赋值的意思

软件运行与内存关系(垃圾数据)

内存是在操作系统的统一管理下使用的

1.软件在运行前需要向操作系统申请存储空间,在内存空闲空间足够时,操作系统将分配一段内存空间并将外存中软件拷贝一份存入该内存空间中,并启动该软件的运行

2.在软件运行期间,该软件所占内存空间将不会分配给其他软件

3.当软件运行完毕后,操作系统将回收该内存空间(注意:操作系统并不清空该内存空间遗留下来的数据),以便再次分配给其他软件使用

综上所述,一个软件所分配到的空间中极可能存在着以前其他软件使用过后的残留数据,这些数据被称之为垃圾数据。使用通常情况下,我们为一个变量,为一个数组,分配好存储空间之后都要对该内存空间初始化(赋值)

如果没有初始化变量,那么输出的就会是遗留下的数据或者是填充值


7.如何定义变量

数据类型 变量名 = 要赋的值

等价于

数据类型 变量名;

变量名 = 要赋的值;

例如: int i = 3;等价于int i; i = 3;

int i,j;等价于int i; int j;

int i,j; i = j = 5;等价于int i,j; i = 5; j = 5;


8.什么叫进制

  • 几进制就是逢几进一
  • N进制就是逢N进一
  • 计算机只能识别二进制
  • C语言规定8进制前要加0,十六进制前要加0x或0X,十进制前不用加

在汇编中:在数字后加字母B表示二进制数,加字母O表示八进制数,加字母D表示十进制数,加字母H表示16进制数 十六进制共十五个元素,即0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F。当满16时向高位进一。如15在16进制中表示F,31在16进制中表示为1F 以下程序是将十进制的某个数转换为十六进制,就以31为例

# include <stdio.h>

int main(void)
{
    int i = 31;

    printf("i = %x\n", i); 
    /*
    %x或%X表示以十六进制输出
    %o表示以八进制输出
    %d表示以十进制输出

    */
    return 0;
}

执行结果如下,输出为1F

BI8H}763SIA118GL`4CP{@6.png


9.常量在C语言中是如何表示的

整数

十进制:传统的写法

十六进制:前面加0x或0X

八进制:前面加0

浮点数

传统的写法

float x = 3.2;

科学记数法 float x = 3.2e3; //x的值为3200

float x = 123.45e-2; //x的值为1.2345

e+数字 = 十的几次方

字符

单个字符用单引号括起来:

'A'表示单个字符A

字符串用双引号括起来:

"A"表示'A'和'\0'的组合


10.常量以什么样的二进制代码存储在计算机中

整数是以补码的形式转化为二进制代码存储在计算机中的

实数是以IEEE754标椎转化为二进制代码存储在计算机中的

字符的存储方式的本质实际也是与整数的存储方式相同:即先将字符用ASCII码转化为整数再以补码的形式转化为二进制代码存储在计算机中


11.代码的规范化

代码规范化的七大原则(转自CSDN博主「End_less__」)

原文出处

代码规范化基本上有七大原则,体现在空行、空格、成对书写、缩进、对齐、代码行、注释七方面的书写规范上。

  1. 空行

空行起着分隔程序段落的作用。空行得体将使程序的布局更加清晰。空行不会浪费内存,虽然打印含有空行的程序会多消耗一些纸张,但是值得。

规则一:定义变量后要空行。尽可能在定义变量的同时初始化该变量,即遵循就近原则。如果变量的引用和定义相隔比较远,那么变量的初始化就很容易被忘记。若引用了未被初始化的变量,就会导致程序出错。

规则二:每个函数定义结束之后都要加空行。

总规则:两个相对独立的程序块、变量说明之后必须要加空行。比如上面几行代码完成的是一个功能,下面几行代码完成的是另一个功能,那么它们中间就要加空行。这样看起来更清晰。

  1. 空格

规则一:关键字之后要留空格。像 const、case 等关键字之后至少要留一个空格,否则无法辨析关键字。像 if、for、while 等关键字之后应留一个空格再跟左括号(,以突出关键字。

规则二:函数名之后不要留空格,应紧跟左括号(,以与关键字区别。

规则三:(向后紧跟;)、,、;这三个向前紧跟;紧跟处不留空格。

规则四:,之后要留空格。如果;不是一行的结束符号,其后要留空格。

规则五:赋值运算符、关系运算符、算术运算符、逻辑运算符、位运算符,如 =、==、!=、+=、-=、* =、/=、%=、>>=、<<=、&=、^=、|=、>、<=、>、>=、+、-、*、/、%、&、|、&&、||、<<、>>、^ 等双目运算符的前后应当加空格。

注意,运算符“%”是求余运算符,与 printf 中 %d 的“%”不同,所以 %d 中的“%”前后不用加空格。

规则六:单目运算符 !、~、++、--、-、*、& 等前后不加空格。

注意:

这里的“-”和规则五里面的“-”不同。这里的“-”是负号运算符,规则五里面的“-”是减法运算符。

这里的“ * ”和规则五里面的“ * ”也不同。这里的“ * ”是指针运算符,规则五里面的“ * ”是乘法运算符。

这里的“&”和规则五里面的“&”也不同。这里的“&”是取地址运算符,规则五里面的“&”是按位与运算符。

总之,规则六中的是单目运算符,而规则五中的是双目运算符,它们是不一样的。

规则七:像数组符号[]、结构体成员运算符.、指向结构体成员运算符->,这类操作符前后不加空格。

规则八:对于表达式比较长的 for 语句和 if 语句,为了紧凑起见,可以适当地去掉一些空格。但 for 和 if 后面紧跟的空格不可以删,其后面的语句可以根据语句的长度适当地去掉一些空格。例如:

for (i=0; i<10; i++)

for 和分号后面保留空格就可以了,=和<前后的空格可去掉。

  1. 成对书写

成对的符号一定要成对书写,如 ()、{}。不要写完左括号然后写内容最后再补右括号,这样很容易漏掉右括号,尤其是写嵌套程序的时候。

  1. 缩进

缩进是通过键盘上的 Tab 键实现的,缩进可以使程序更有层次感。原则是:如果地位相等,则不需要缩进;如果属于某一个代码的内部代码就需要缩进。

  1. 对齐

对齐主要是针对大括号{}说的:

规则一:{和}分别都要独占一行。互为一对的{和}要位于同一列,并且与引用它们的语句左对齐。

规则二:{}之内的代码要向内缩进一个 Tab,且同一地位的要左对齐,地位不同的继续缩进。

还有需要注意的是,很多编程软件是会“自动对齐”的,比如:

#include <stdio.h>
int main(void)
{
    if (…)
    return 0;
}

写完 if 那一行后,按回车,此时光标在括号的右边,而此 if 下的大括号要写在与 if 左对齐的正下方,通常我们是按一下 Backspace 键使光标停在与 if 左对齐的正下方。但事实上我们不需要这样做,我们直接输入大括号即可,系统会自动对齐到与 if 左对齐的正下方。再接着看:

#include <stdio.h>
int main(void)
{
    if (…)
    {
        while (…)
    }
    return 0;
}

写完 while 那一行后,按回车,此时光标不是停在与 while 左对齐的正下方,同样,我们不需要按 Backspace,直接输入大括号即可,系统会自动对齐到与 while 左对齐的正下方的。

此外编程软件还有“对齐、缩进修正”功能。就是按 Ctrl+A 全选,然后按 Alt+F8,这时程序中所有成对的大括号都会自动对齐,未缩进的也会自动缩进。不管是在编程过程中,还是在编写结束完之后,都可以使用这个技巧。但如果完全按照规范写,那根本就不需要这个技巧,所以,这只是一个辅助功能。

  1. 代码行

规则一:一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且便于写注释。

规则二:if、else、for、while、do 等语句自占一行,执行语句不得紧跟其后。此外,非常重要的一点是,不论执行语句有多少行,就算只有一行也要加{},并且遵循对齐的原则,这样可以防止书写失误。

  1. 注释

C语言中一行注释一般采用//…,多行注释必须采用//。注释通常用于重要的代码行或段落提示。在一般情况下,源程序有效注释量必须在 20% 以上。虽然注释有助于理解代码,但注意不可过多地使用注释。

规则一:注释是对代码的“提示”,而不是文档。程序中的注释不可喧宾夺主,注释太多会让人眼花缭乱。

规则二:如果代码本来就是清楚的,则不必加注释。例如:

i++; //i加1 这个就是多余的注释。

规则三:边写代码边注释,修改代码的同时要修改相应的注释,以保证注释与代码的一致性,不再有用的注释要删除。

规则四:当代码比较长,特别是有多重嵌套的时候,应当在段落的结束处加注释,这样便于阅读。

规则五:每一条宏定义的右边必须要有注释,说明其作用。

实际案例 下面我们给出一段求一元二次方程的代码,让大家实际感受一下。虽然这个程序不包含所有的规范,但一些包含的规范我们可以对照着看看。

以下程序的功能是把任何一个一元二次方程 ax2+bx+c=0 的解给求出来。

# include <stdio.h>
# include <math.h> /*因为要用到求平方函数sqrt(),所以要包含头文件 math.h*/
int main( )
{
	//把三个系数保存到计算机中
	int a = 1; // “=”不表示相等,而是表示赋值
	int b = 2;
	int c = 1;
	double delta; //delta存放的是b*b - 4*a*c的值
	double x1, x2; //分别用于存放一元二次方程的两个解
	delta = b * b - 4 * a*c;
	if (delta > 0)
	{
		x1 = (-b + sqrt(delta)) / (2 * a);
		x2 = (-b - sqrt(delta)) / (2 * a);
		printf("该一元二次方程有两个解,x1 = %f, x2 = %f\n", x1, x2);
	}
	else if (0 == delta)
	{
		x1 = (-b) / (2 * a);
		x2 = x1; //左边值赋给右边
		printf("该一元二次方程有一个唯一解,x1 = x2 = %f\n", x1);
	}
	else
	{
		printf("无解\n");
	}
	return 0;
}


12.什么是字节

字节就是存储数据的单位,并且是硬件所能访问的最小单位

1字 = 2字节

1字节 = 8位二进制

1字 = 16位二进制

1KB = 1024个字节

1MB = 1024KB

1GB = 1024MB

1TB = 1024GB


13.不同类型数据之间相互赋值的问题(转自CSDN博主「QCZTZSWT357」的原创文章)

原文出处

整数与整数之间

一、长度相等(在内存中存储的位数相等)的两个不同的类型的数据之间的赋值

在计算机中的存储内容不变,只是数据按照不同的编码格式来解析。

二、长 赋值给 短 (短 = 长)

截取低位,然后按照短整数的数据类型解析。

三、短 赋值给 长 (长 = 短) 其中,短转长又分为三种情况:

  1. 两个数据都是无符号的数据,短整数直接高位补0。

  2. 两个数据都是有符号的数据,短整数进行符号位扩展。

  3. 两个数一个是有符号数,一个数是无符号数,那么先将短整数进行位数扩展,过程中保持数值不变,然后按照长整数的数据类型解析数据。

整数与浮点之间

浮点数转整数

截取整数部分,赋值给a

int a = 3.54

a 的值为 3

整数转浮点数

小数部分为0,整数部分的值与其整数的值相等。

float b = 3;

b 的值是 3.0

float 与 double 之间

double 转 float 将会丢失精度。

float 转 double 值不变。

注:整数在计算机中都是以补码的形式存储的。


14.什么是ASCII+字符本质上与存储方式的相同

ASCII码不是一个值,是一种规定,规定了不同的字符使用哪个整数值去表示

以下是ASCII码表

二进制十进制十六进制字符/缩写解释
00000000000NUL (NULL)空字符
00000001101SOH (Start Of Headling)标题开始
00000010202STX (Start Of Text)正文开始
00000011303ETX (End Of Text)正文结束
00000100404EOT (End Of Transmission)传输结束
00000101505ENQ (Enquiry)请求
00000110606ACK (Acknowledge)回应/响应/收到通知
00000111707BEL (Bell)响铃
00001000808BS (Backspace)退格
00001001909HT (Horizontal Tab)水平制表符
00001010100ALF/NL(Line Feed/New Line)换行键
00001011110BVT (Vertical Tab)垂直制表符
00001100120CFF/NP (Form Feed/New Page)换页键
00001101130DCR (Carriage Return)回车键
00001110140ESO (Shift Out)不用切换
00001111150FSI (Shift In)启用切换
000100001610DLE (Data Link Escape)数据链路转义
000100011711DC1/XON (Device Control 1/Transmission On)设备控制1/传输开始
000100101812DC2 (Device Control 2)设备控制2
000100111913DC3/XOFF (Device Control 3/Transmission Off)设备控制3/传输中断
000101002014DC4 (Device Control 4)设备控制4
000101012115NAK (Negative Acknowledge)无响应/非正常响应/拒绝接收
000101102216SYN (Synchronous Idle)同步空闲
000101112317ETB (End of Transmission Block)传输块结束/块传输终止
000110002418CAN (Cancel)取消
000110012519EM (End of Medium)已到介质末端/介质存储已满/介质中断
00011010261ASUB (Substitute)替补/替换
00011011271BESC (Escape)逃离/取消
00011100281CFS (File Separator)文件分割符
00011101291DGS (Group Separator)组分隔符/分组符
00011110301ERS (Record Separator)记录分离符
00011111311FUS (Unit Separator)单元分隔符
001000003220(Space)空格
001000013321! 
001000103422" 
001000113523# 
001001003624$ 
001001013725% 
001001103826& 
001001113927' 
001010004028( 
001010014129) 
00101010422A* 
00101011432B+ 
00101100442C, 
00101101452D- 
00101110462E. 
00101111472F/ 
0011000048300 
0011000149311 
0011001050322 
0011001151333 
0011010052344 
0011010153355 
0011011054366 
0011011155377 
0011100056388 
0011100157399 
00111010583A: 
00111011593B; 
00111100603C< 
00111101613D= 
00111110623E 
00111111633F? 
010000006440@ 
010000016541A 
010000106642B 
010000116743C 
010001006844D 
010001016945E 
010001107046F 
010001117147G 
010010007248H 
010010017349I 
01001010744AJ 
01001011754BK 
01001100764CL 
01001101774DM 
01001110784EN 
01001111794FO 
010100008050P 
010100018151Q 
010100108252R 
010100118353S 
010101008454T 
010101018555U 
010101108656V 
010101118757W 
010110008858X 
010110018959Y 
01011010905AZ 
01011011915B[ 
01011100925C\ 
01011101935D] 
01011110945E 
01011111955F_ 
011000009660` 
011000019761a 
011000109862b 
011000119963c 
0110010010064d 
0110010110165e 
0110011010266f 
0110011110367g 
0110100010468h 
0110100110569i 
011010101066Aj 
011010111076Bk 
011011001086Cl 
011011011096Dm 
011011101106En 
011011111116Fo 
0111000011270p 
0111000111371q 
0111001011472r 
0111001111573s 
0111010011674t 
0111010111775u 
0111011011876v 
0111011111977w 
0111100012078x 
0111100112179y 
011110101227Az 
011110111237B{ 
011111001247C 
011111011257D} 
011111101267E~ 
011111111277FDEL (Delete)删除

用%d会直接输出代表该字符的整数,而用%c会输出该代表这个字符的整数对应的字符(也就是自己本身)因为字符本质上是以代表它的数字转换的二进制码存储的。


二.printfscanf的用法

printf用法

《C Prinmer Plus》中对printf()的介绍和我自己的总结:圆括号表示printf的一个函数名。圆括号中的内容是从main()函数传递给printf()函数的信息。该信息被称为参数,若这个参数是一个特定的值也可以被称为实际参数,若这个参数是一个存储值的变量就可以被称为形式参数,printf()这个函数会查看在圆括号中的双引号里的内容并且打印在屏幕上(注意:换行符/n不会被打印而会被执行,/t,/b同理)具体可查看书中p24内容

关于利用printf输出数据的进制转换

# include <stdio.h>

int main(void)
{
    int i = 31;

    printf("%x\n", i);  //输出结果是:  2f
    printf("%X\n", i); //输出结果是:  2F
    printf("%#x\n", i); //输出结果是:  0x2f
    printf("%#X\n", i); //输出结果是:  0X2F
    
    
    return 0;
}

以下几种格式

1.printf("字符串");

2.printf("输出控制符", 输出参数);

3.printf("输出控制符1 输出控制符2...",输出参数1 输出参数2); //输出控制符个数必须和输出参数个数一致并且对应

4.printf("输出控制符 非输出控制符",输出参数);

输出控制符包含如下

%d

%ld

%c

%f

%lf

%x(或者%x或者%#x或者%#X)

%o

为什么需要输出控制符

1.二进制代码可以表示数据也可以表示指令

2.如果二进制代码表示的数据的话,那么同样二进制代码组合以不同的输出格式输出就会有不同的输出结果


scanf用法

scanf()【通过键盘将数据输入到变量中】

# include <stdio.h>

int main(void)
{
    int i;

    scanf("%d", &i); //&i 表示i的地址 &是一个取地址符
    printf("i = %d\n", i); 

    
    return 0;
}

可以改变输出控制符和输入控制符来改变代码的功能进行调试

scanf()圆括号内加入非输入控制符来规定输入的值入:m%d就是必须先输入m再输入数值

两种用法

用法一:scanf("输入控制符", 输入参数);

功能: 将从键盘输入的字符转化为输入控制符所规定格式的数据,然后存入以输入参数的值为地址的变量中

用法二:scanf("非输入控制符 输入控制符", 输入参数);

功能: 将从键盘输入的字符转化为输入控制符所规定格式的数据,然后存入以输入参数的值为地址的变量中 非输入控制符必须原样输入

一次给多个变量键盘赋值
# include <stdio.h>

int main(void)
{
    int i, j;

    scanf("%d %d", &i &j);
    printf("i = %d, j = %d\n", i, j); 

    
    return 0;
}

可以加入非输入控制符限定输入内容进行调试

如何使用scanf编写出高质量代码

1.使用scanf之前最好使用printf来提示用户以什么样的方式来输入

2.scanf中尽量不要使用非输入控制符,尤其是不要用\n(换行符\n在scanf圆括号的双引号中只代表字符没有特殊含义不作为换行符)

三.pastebin分享代码的链接、名词翻译以及课后作业

使用Ubuntupastebin分享的代码链接

名词翻译

中文英文中文英文
整数Integer变量variable
字符Character初始化initialization
浮点数Floating point十进制decimal
结构体Structure二进制Binary
枚举Enumerate十六进制hex
联合Joint打印printing

课后作业

  • 3.10 第四题 第六题前6个 第八题 指出下列常量的类型和含义:

a. '\b' 代表退格键

b. 1066整数1066

c. 99.44实数99.44

d. 0XAA十六进制值AA

写出下列常量在声明中使用的数据类型和在printf()中对应的转换说明:

常量类型转换说明(%转换字符)
12整数%d
0X3十六进制数/x或/X或/#x或/#X
'C'字符%c
2.34E07整数或浮点数的科学记数法%d
'\040'字符的八进制%n
7.0浮点数%d
  • 3.11 第一题 第二题 通过实验(即编写带有此类问题的程序)观察系统如何处理整数上溢、浮点数上溢和浮点数下溢的情况。

编写一个程序,要求提示输入一个ASCII码值(如,66),如何打印输入的字符。

  • 4.8 第一题 第四题 第七题 编写一个程序,提示用户输入名和姓,如何以“名,姓”的格式打印出来。

编写一个程序,提示用户输入身高(单位:英寸)和姓名,如何以指数计数法打印。用下面的格式显示用户刚输入的信息:

Dabney, you are 6.208 feet tall

使用float类型,并用/作为除号。如果你愿意,可以要求用户以厘米为单位输入身高,并以米为单位显示出来。

编写一个程序,将一个double类型的变量设置为1.0/3.0,一个float类型的变量设置为1.0/3.0.分别显示两次计算的结果各3次:一次显示小数点后面6位数字; 一次显示小数点后面12位数字;一次显示小数点后面16位数字。程序中要包含float.h头文件,并显示FLT_DIG 和 DBL_DIG的值。1.0/3.0的值与这些只一致吗?