从零开始学C语言
@阆苑祁寒
更新时间:2019-09-13
写在前面:本文从一个初学者的角度,给出了对C语言的简单理解。如有谬误,敬请指出!
Week1——基本语法
1 #include
2 int main(void)
3 {
4 printf("Hello, world! /n");
5 return 0;
6 }
基本语法解释:
- stdio 系统文件库,除stdio有诸多类型的库函数,stdio中最常用的是printf()函数。
- .h 头文件
- #include 预处理器导入头文件,可python的inform和latex的\usepackage是一个道理.
- <> C标准库,写成""表示自定义的库,常见的有标准数据传输库
和数学库 ,具体参考相关附录. - int 返回一个整数,表示整型数据结构,还有其他种类的数据结构,对应到二进制,拥有巧妙的运算规则.有以下几种类型:字符型(char)→整型(int: short/long/long long; signed/unsigned)→浮点型(float,double,long double),需要特别注意常量的类型和数值溢出(精度)这两个问题.
- main 所有C文件有且只有一个主函数(入口函数),在C++中main()表示不需要参数,在C中main(void)表示不需要参数(当然前一种情况也可以运行),注意没有void main这种说法,int main(int argc, char *argv[])表示需要参数,argc为给程序的参数的个数,argv中保存的是给函数的参数,都是字符串。
- printf() 输出到屏幕,必须调用头文件
,是标准数据传输库下两个最重要的函数(另外一个是scanf,格式与printf类似,只是参量表前需要加地址符&),其调用格式是 printf("<格式化字符串>", <参量表>); ,库函数的声明是 int printf(const char *format, ...) ,其中字符串format包含了要被写入到标准输出 stdout 的文 本,可以包含嵌入的 format 标签,其标签属性是 %[name][flags][width][.precision][length]specifier ,可被随后的附加参数中指定的值替换,并按需求进行格式化。注意每一个printf()可以有多个format标签,写成 %[name]%[name] 格式,中间无需逗号。(注:scanf函数可以识别的数据类型是 [number] [number] (空格输入)和 [number]\n[number] (换行输入),特别,中间如果是逗号则不能识别。)更多内容参考下表(摘自附录):
name | 意义 |
---|---|
d | 以十进制形式输出带符号整数(正数不输出符号) |
o | 以八进制形式输出无符号整数(不输出前缀0) |
x,X | 以十六进制形式输出无符号整数(不输出前缀Ox) |
u | 以十进制形式输出无符号整数 |
f | 以小数形式输出单、双精度实数 |
e,E | 以指数形式输出单、双精度实数 |
g,G | 以%f或%e中较短的输出宽度输出单、双精度实数 |
c | 输出单个字符 |
s | 输出字符串 |
p | 输出指针地址 |
lu | 32位无符号整数 |
llu | 64位无符号整数 |
flags | 意义 |
---|---|
- | 在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。 |
+ | 强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。 |
空格 | 如果没有写入任何符号,则在该值前面插入一个空格。 |
# | 与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。 与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。 与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。 |
0 | 在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。 |
width | 意义 |
---|---|
(number) | 要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断。 |
* | 宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。 |
.precision | 意义 |
---|---|
.number | 对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。 对于 e、E 和 f 说明符:要在小数点后输出的小数位数。 对于 g 和 G 说明符:要输出的最大有效位数。 对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。 对于 c 类型:没有任何影响。 当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。 |
.* | 精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。 |
length | 意义 |
---|---|
h | 参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。 |
l | 参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。 |
L | 参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。 |
- return 0 参量为空时结束循环(为了使代码严谨,必须要加)。return表示返回一个函数的值,在C中没有真假值一说,与python不同,即没有return false和return ture,返回函数return参见后续内容。
- /n 是C语言中的转义字符,借助/以示与字符(参见ASCII表)的区别。更多内容参考下表(摘自附录):
- C标识符 区分大小写,不允许出现除"_"之外的特殊字符(参见ASCII表),为避免与常量的区别,禁止用数字开头,通常由写为"(字母)_(数字)"的形式,且字母要求具有一些明确的含义,不可选用关键字。原则上,可以选用一些库函数中的函数名,但是没有必要,徒增混乱!
- C注释 单行可以用\\注释,多行可以用\*和*\注释,后者更为规范,其本质是预编译时以一个空格代之(搜索\*和*\,也是不能嵌套的原因)。
- ; C语句结束语,否则需要用{}括起来。
- C关键字 不能作为常量名、变量名或其他标识符名称。更多内容参考下表(摘自附录),并注明不常见的关键字。
auto | 声明自动变量 |
break | 跳出当前循环 |
case | 开关语句分支 |
char | 声明字符型变量或函数返回值类型 |
const | 声明只读变量 |
continue | 结束当前循环,开始下一轮循环 |
default | 开关语句中的"其它"分支 |
do | 循环语句的循环体 |
double | 声明双精度浮点型变量或函数返回值类型 |
else | 条件语句否定分支(与 if 连用) |
enum | 声明枚举类型 |
extern | 声明变量或函数是在其它文件或本文件的其他位置定义 |
float | 声明浮点型变量或函数返回值类型 |
for | 一种循环语句 |
goto | 无条件跳转语句 |
if | 条件语句 |
int | 声明整型变量或函数 |
long | 声明长整型变量或函数返回值类型 |
register | 声明寄存器变量 |
return | 子程序返回语句(可以带参数,也可不带参数) |
short | 声明短整型变量或函数 |
signed | 声明有符号类型变量或函数 |
sizeof | 计算数据类型或变量长度(即所占字节数) |
static | 声明静态变量 |
struct | 声明结构体类型 |
switch | 用于开关语句 |
typedef | 用以给数据类型取别名 |
unsigned | 声明无符号类型变量或函数(正数) |
union | 声明共用体类型 |
void | 声明函数无返回值或无参数,声明无类型指针 |
volatile | 说明变量在程序执行中可被隐含地改变 |
while | 循环语句的循环条件 |
- 空格 描述空白符、制表符、换行符和注释,空格分隔语句的各个部分,让编译器能识别语句中的某个元素(如int)在哪里结束,下一个元素在哪里开始。同时也是ASCII表中的特殊字符,由于在C语言中具有特殊的意义,故列出。
- 函数与存储类型 除主函数main之外的其他函数,需要命名为除main之外的名字以便识别,常见写法为“函数名(需要返回的数据类型和参量)”(C99之后的存储类型没有必要写出),这里的参量与函数内局部声明的参量不同(需要返回!),这也是当参量为空时写return 0的原因。更多地,计算机硬件部分分为外存→内存→快存(cache,预测CUP动作,算法固定,不受人工干预)→寄存器(与CPU伴生,存储中间运算过程),调用速度是递增的,存储类型分为"内存"和"寄存器"两种类型,默认是"内存",故没必要写出。
- 引号 单引号表示一个字符,双引号表示字符串(指针),前者被编译为字符编码(注意ASCII表中的对应关系,也即char类型),后者被编译为内存,有关指针的内容在后续指出。
1.利用星号和空格输出一个爱心形状。2.键盘输入x的值,求方程y=x*x+2*x-10所对应的y值。3.以下程序求两个输入的整数的和,请找出其中的错误。题目3的代码1 #include
2 3 int main() 4 { 5 int a,b,sum; 6 7 sum=a+b; 8 a=1; 9 b=2; 10 11 printf("sum=%d\n",sum); 12 } 4.以下程序求1到100的和,请找出其中的错误。
题目4的代码1 #include
2 3 int main() 4 { 5 int a,i,sum; 6 7 i=0; 8 while(i<=100) 9 { 10 sum=sum+i; 11 i=i+1; 12 } 13 14 printf("1+2+...+100=%d\n",sum); 15 16 } 5.已知在某C语言编译系统中表达式 sizeof(int) 的值是2,如果希望将常量-70000正确的保存在一个变量a中,该变量声明语句应当是( )
A. int a; B. long int a;
C. unsigned int a; D. unsigned long int a;6.设int类型的数据长度为2个字节,则unsigned int类型数据的取值范围是( )
A.0~255 B.0~65535
C.-32768~32767 D.-256~2557.在C语言中,数字029是一个( )
A.八进制数 B.十六进制数
C.十进制数 D.非法数8.以下标识符中不能用做变量名或自定义函数名的是( )
A. main B. scanf C. _float D. sizeof
9.在以下各组标识符中,均可以用作变量名的一组是( )
A. A01, Int B. table_1, a *.1
C. 0_a, W12 D. for, point10.以下叙述中正确的是( )
A. 在C程序中,main函数必须位于程序的最前面
B. C程序的每行只能写一条语句
C. C语言本身没有输入输出语句
D. 在对一个C程序进行编译的过程中,可发现注释中的拼写错误11.以下叙述不正确的是( )
A. 一个C源程序可由一个或多个函数组成
B. 一个C源程序必须包含一个main函数
C. C程序的基本组成单位是函数
D. 在C程序中,注释说明只能位于一条语句的后面12.C语言规定:在一个源程序中,main函数的位置( )
A. 必须在最开始
B. 必须在系统调用的库函数的后面
C. 可以任意
D. 必须在最后13.编写程序,判断并输出所使用的编译器每种基本类型变量所占的存储空间大小。
14.编写程序,输入一个长方体的长、宽和高(整数),输出这个长方体的体积。
15.编写程序,读取一个在0和1000之间的整数,并将该整数的各位数字相加。
16.编写程序,提示用户输入分钟数(例如10000000),然后显示这些分钟代表的时长(多少年多少天),为了简化问题,假设一年有365天。
17.编写程序,计算将水从初始温度加热到最终温度所需的能量Q=M×(最终温度 – 初始温度)× 4184。
18.编写程序,从键盘输入一个4位正整数,输出该数的反序数。
19.一个美国政府的研究实验室得出结论,认为在肥宅快乐水中常用的人造甜味剂会导致实验室老鼠的死亡。你的一个朋友在拼命的减肥,但是他不能放弃肥宅快乐水。你的朋友想知道能够喝多少汽水而不会导致死亡。请编写程序,帮他回答这个问题。已知实验时,杀死一只老鼠所用的人造甜味剂是5g,老鼠的重量为35g。假设老鼠的致死量(lethal dose)成比例对应于人的致死量。一罐肥宅快乐水350g,其中所含的人造甜味剂占0.1%。输入你的朋友的体重(Kg),输出他最多可以喝的肥宅快乐水的罐数。
20.(未完待续)
- 表达式语句:赋值和调用函数。
- 复合语句:用{}括出,通常含局部声明和语句两部分。
- 空语句:例如连续输入字符,遇到a则停止,可用getchar表示, while(getchar()!='a'); 。
优先级
|
运算符
|
名称或含义
|
使用形式
|
结合方向
|
说明
|
1
|
[]
|
数组下标
|
数组名[整型表达式]
|
左到右
|
|
()
|
圆括号
|
(表达式)/函数名(形参表)
|
|||
.
|
成员选择(对象)
|
对象.成员名
|
|||
->
|
成员选择(指针)
|
对象指针->成员名
|
|||
2
|
-
|
负号运算符
|
-算术类型表达式
|
右到左
|
单目运算符
|
(type)
|
强制类型转换
|
(纯量数据类型)纯量表达式
|
|||
++
|
自增运算符
|
++纯量类型可修改左值表达式
|
单目运算符
|
||
--
|
自减运算符
|
--纯量类型可修改左值表达式
|
单目运算符
|
||
*
|
取值运算符
|
*指针类型表达式
|
单目运算符
|
||
&
|
取地址运算符
|
&表达式
|
单目运算符
|
||
!
|
逻辑非运算符
|
!纯量类型表达式
|
单目运算符
|
||
~
|
按位取反运算符
|
~整型表达式
|
单目运算符
|
||
sizeof
|
长度运算符
|
sizeof 表达式
sizeof(类型)
|
|||
3 |
/
|
除
|
表达式/表达式
|
左到右 |
双目运算符
|
*
|
乘
|
表达式*表达式
|
双目运算符
|
||
%
|
余数(取模)
|
整型表达式%整型表达式
|
双目运算符
|
||
4
|
+
|
加
|
表达式+表达式
|
左到右
|
双目运算符
|
-
|
减
|
表达式-表达式
|
双目运算符
|
||
5
|
<<
|
左移
|
整型表达式<<整型表达式
|
左到右
|
双目运算符
|
>>
|
右移
|
整型表达式>>整型表达式
|
双目运算符
|
||
6
|
>
|
大于
|
表达式>表达式
|
左到右
|
双目运算符
|
>=
|
大于等于
|
表达式>=表达式
|
双目运算符
|
||
<
|
小于
|
表达式<表达式
|
双目运算符
|
||
<=
|
小于等于
|
表达式<=表达式
|
双目运算符
|
||
7
|
==
|
等于
|
表达式==表达式
|
左到右
|
双目运算符
|
!=
|
不等于
|
表达式!= 表达式
|
双目运算符
|
||
8
|
&
|
按位与
|
整型表达式&整型表达式
|
左到右
|
双目运算符
|
9
|
^
|
按位异或
|
整型表达式^整型表达式
|
左到右
|
双目运算符
|
10
|
|
|
按位或
|
整型表达式|整型表达式
|
左到右
|
双目运算符
|
11
|
&&
|
逻辑与
|
表达式&&表达式
|
左到右
|
双目运算符
|
12
|
||
|
逻辑或
|
表达式||表达式
|
左到右
|
双目运算符
|
13
|
?:
|
条件运算符
|
表达式1? 表达式2: 表达式3
|
右到左
|
三目运算符
|
14
|
=
|
赋值运算符
|
可修改左值表达式=表达式
|
右到左
|
|
/=
|
除后赋值
|
可修改左值表达式/=表达式
|
|||
*=
|
乘后赋值
|
可修改左值表达式*=表达式
|
|||
%=
|
取模后赋值
|
可修改左值表达式%=表达式
|
|||
+=
|
加后赋值
|
可修改左值表达式+=表达式
|
|||
-=
|
减后赋值
|
可修改左值表达式-=表达式
|
|||
<<=
|
左移后赋值
|
可修改左值表达式<<=表达式
|
|||
>>=
|
右移后赋值
|
可修改左值表达式>>=表达式
|
|||
&=
|
按位与后赋值
|
可修改左值表达式&=表达式
|
|||
^=
|
按位异或后赋值
|
可修改左值表达式^=表达式
|
|||
|=
|
按位或后赋值
|
可修改左值表达式|=表达式
|
|||
15
|
,
|
逗号运算符
|
表达式,表达式,…
|
左到右
|
从左向右顺序结合
|
- 运算符运算:括号>单目>算术>关系>逻辑>赋值,以及多目运算.
- if语句: if(){;}else (if){;} ,允许嵌套.
- switch语句:多种情况的另一种表示法 switch(){case (int型) : (语句);[break;]default: (语句);} ,允许嵌套.
- while语句: while((控制语句)){;} ,允许嵌套.
- do-while语句: do{;}while((控制语句)); ,允许嵌套.
- for语句:for((初值);(控制语句);(控制变量)){;} ,允许嵌套.
- 嵌套语句:与选择结构嵌套.
- break语句:结束switch语句中的cases或者结束循环结构,适用于非结构化语句.
- continue语句:强制开启新一轮循环,没有break语句方便高效,适用于非结构化语句.
- 无条件转移语句:goto转向语句编号代表的循环,需要对循环结构编号,容易使程序结构混乱.