2020-09-19 | 代码如诗 | UNLOCK

基础结构——C语言程序设计笔记(一)

趁着假期呢看了一些中国大学MOOC中浙江大学翁恺教授的C语言程序设计,也算是预习大学课程吧。因为有一点编程基础因此前边一些听起来也不是很吃力,因此前边很多章节都没有记笔记,准备记在一起(其实是懒得记吧hhh)

浙江大学-C语言程序设计

C语言笔记目录

  1. 基础结构——C语言程序设计笔记(一)
  2. 指针——C语言程序设计笔记(二)
  3. 字符串——C语言程序设计笔记(三)
  4. 结构类型——C语言程序设计笔记(六)
  5. 程序结构——C语言程序设计笔记(六)
  6. 文件——C语言程序设计笔记(六)
  7. 链表——C语言程序设计笔记(六)

下一篇笔记

指针——C语言程序设计笔记(二)

程序设计与C语言

C语言是一门古老的、低级的、底层的、面向过程的语言

HelloWorld

1
2
3
4
5
6
7
#include <stdio.h>

int main()
{
printf("Hello World\n");
return 0;
}

程序从main函数开始,如上是最基础的Hello World

通常来说C语言是编译-运行的

输入输出

在C语言中,使用printf()函数来输出内容,其中,传递给printf的参数是:

1
2
3
int i = 64;
printf("字符串\n");
printf("格式字符,比如%d", i);

运行程序会输出:

1
2
>字符串
>格式字符,比如64

格式字符是%+一个或多个字符,用于控制输出的格式。比如说,后面传入的参数i是int类型的,那么使用%d来输出整数

常见的格式字符有:

格式字符

更多的用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int i = 64;
int *p = i;
double d = 32.64128;
char c = 'c';
printf("%s\n", "HelloWorld");
// %s:字符串
printf("%c\n", c);
// %c:字符
printf("%d\n", i);
// %d:整数(十进制)
printf("%5d\n", i);
// %5d:五位整数,不足五位前面补充空格
printf("%05d\n", i);
// %05d:五位整数,不足五位前面补充0
printf("%-5d\n", i);
// %-5d:五位整数,不足五位后面补充空格
printf("%u\n", i);
// %u:打印无符号数
printf("%x\n", i);
// %x:整数(十六进制)
printf("%o\n", i);
// %o:整数(八进制)
printf("%f\n", d);
// %f:浮点数
printf("%0.0f", d);
// %0.0f不保留小数
printf("%0.100f", d);
// %0.100保留三位小数
printf("%p");
// %p取指针的地址

输出大致如下(其中%p的例子仅做示范,“□”代表空格):

1
2
3
4
5
6
7
8
9
10
11
12
13
HelloWorld
c
64
□□□64
00064
64□□□
64
40
100
32.64128
32
32.641
0x7fff5cc109d4

更多情况见C语言格式字符(还没写先挖坑)

C语言使用scanf()函数来获取输入,其中的参数是格式字符,另外一个参数是&变量名(&是取地址)

转义(逃逸)字符

常见转义字符有:

\n:换行

\t:制表符

\":"

\':'

\\:\

转义字符

计算

在C语言中这样定义变量:

1
变量类型 变量名;

可以在变量定义的时候给其赋值,否则不会初始化

1
int myVar = 64;

在这中等号代表赋值而不是相等

变量区分大小写,即myvar和myVar完全是不同的两个变量

使用typeof()函数可以输出变量占据的字节,typeof是静态的,括号里面的运算不会被进行

在C语言中有多种运算符常见的有+、-、、\、以及+=、-=、=、+和++、–

判断

if语句用于判断,其结构如下

1
2
3
4
5
6
7
8
9
10
11
12
if (/*条件*/)
{
// 语句;
}
else if (/*条件*/)
{
// 语句;
}
else
{
// 语句;
}

if是可以嵌套的

在条件中判断值是否相等使用“==”而不是“=”,单个的等号是赋值运算。括号内1表示是,0表示非。

比如说

1
int result = 3 < 6;

条件成立则3 < 6 的结果为1即result的值为1

else if等同于:

1
2
3
4
5
6
7
8
9
10
11
12
if (/*条件1*/)
{
// 语句;
}
else
{
if (/*条件2*/)
{
// 语句;
}
...
}

虽然单行的语句可以不使用{},但是建议使用

switch case语句的结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
switch (/*变量*/)
{
case '0':
{
// 语句1;
}
case '1':
{
// 语句2;
break;
}
default:
{
// 语句;
}
}

switch的作用是根据变量的值将代码跳转到某个地方,如果case后面没有break;那么会接着走下一行

循环

while

1
2
3
4
while (/*条件*/)
{
// 执行语句;
}

while循环的过程如下:

  1. 判断是否满足条件
  2. 满足条件进入循环体,执行语句;不满足条件则跳出
  3. 返回1

do while

1
2
3
4
5
do
{
// 执行语句;
}
while (/*条件*/)

do while循环的过程如下:

  1. 执行语句
  2. 判断是否满足条件,满足条件返回1;不满足条件则跳出
1
2
3
4
for(/*表达式1*/;/*表达式2*/;/*表达式3*/)
{
// 执行语句;
}

for循环是一种古老的循环(所以它看起来比较怪),它的执行过程如下:

  1. 求解表达式1(通常是初始化计数变量)
  2. 求解表达式2(其实是条件),符合条件继续运行,不符合则跳出
  3. 执行语句
  4. 求解表达式3(通常是计数变量)
  5. 回到2步执行

也就是for循环改写成while相当于:

1
2
3
4
5
6
7
// 表达式1;
while (/*表达式2*/)
{
// 执行语句;
// ...
// 表达式3;
}

在很多时候使用for循环会很方便(虽然我没感觉但是代码短了)

比如需要计数时

1
2
3
4
5
for (int i = 1; i <= 100; i++)
{
printf("%d", i);
}
// 从1数到100

数据类型

整型

char
short
int
long
long long

浮点数

float
double
long double

浮点类型的选择

!注意:浮点数是有精度的,它们可能不是准确的,制作计算器程序应该使用BCD

其实个人觉得整型也是一个道理,通常来说只用int就行了

逻辑

bool

bool类型只有true和false两个值,使用bool需要添加头文件<stdbool.h>

bool

整数的二进制表示

在计算机内部所有变量都是二进制的。

为了表示负数,使用了补码,比如:

-1为 11111111

1 为 00000001

进行二进制加法时,11111111 + 00000001 = 100000000

然而,进位上去的1被舍弃了,从而实现 -1 + 1 = 0

整数的范围

如果某个类型占据n个字节

那么它的范围是 -2^(n-1)~2^(n-1)-1

// 这里的"^"表示次幂而不是异或

字符类型char

char既是整型数字又是字符,将字符赋值给char时应该用单引号” ‘ “包裹,比如

1
char ch = 'a';

可以将字符作为整数输出、计算、输入,字符的整数值是它的ASCII码

ASCII码对照表和转换器

逻辑运算

&&逻辑且

当逻辑且左右的条件全成立时返回1,否则返回0

||逻辑或

当逻辑或两侧任意的一个条件成立时返回1,全不成立则返回0

强制类型转换

C语言会将小范围->大范围的做自动类型转换,比如说5/7.0(int\double)结果是double

在C语言中使用(类型)变量来做强制类型转换,比如说

1
(int*)malloc(sizeof(int)*4);

函数

函数的定义

其实int main()就是函数

1
2
3
4
5
int myFunc(int foot,int inch /*参数表*/ )        // 函数头
{
int ret = (int)((foot + inch/12.0)*0.3); // 函数体
return ret;
}

函数由以下内容构成:

1
2
3
<数据类型> <函数名>(<参数表>){
// 语句
}

如果把函数定义在main函数的后面则需要在main函数的前面声明函数原型(其实就是把函数头copy过去并改成分号结尾)以便于编译器“认出”函数

使用void定义一个不返回值的函数,不能用return语句

!注意:使用函数时有多个可以return的时候建议遵循单一出口原则,即定义一个本地变量(通常叫做ret)来存储结果,然后最后返回这个本地变量

调用函数时传递的参数是值而不是变量本身,在函数内修改传过去的变量不会对main中的变量造成影响(指针除外)

数组

数组的定义

可以使用以下形式定义一个数组

1
int arrayInt[30];

这个数组具有30个单元,通过arrayInt[i]来访问,索引从0开始,不能超过30 - 1,否则数组会越界

数组的初始化

可以在定义时去初始化数组:

1
int arrayInt[4] = {0, 3, 9, 2,};

这样初始化会使得数组被赋值为大括号中的数字,如下:

1
2
3
4
arrayInt[0] = 0;
arrayInt[1] = 3;
arrayInt[2] = 9;
arrayInt[3] = 2;

使用

1
int arrayInt[] = { /* ... */ };

来创建自动设置大小的数组

!注意:这样的数组大小仍然是固定的,只是在初始化的时候根据大括号内容自动算了大小

使用

1
int arrayInt[5] = {[1] = 3,};

来创建指定单元被初始化为指定值的数组

使用

1
int arrayInt[5] = {0,};

来让整个数组的每个单元初始化为0(实际上,当大括号内的数字数量比数组的大小小时,会默认填充每个单位为0)

数组的运算

数组不能由一个数组赋值给另外一个数组

数组的每个单元都可以进行运算

二维数组

使用

1
int a[5][3];

来定义一个二维数组,可以把它看成是一个5行3列表格(或者矩阵)

1 2 3
a[0][0] a[0][1] a[0][2]
a[1][0] a[1][1] a[1][2]
a[2][0] a[2][1] a[2][2]
a[3][0] a[3][1] a[3][2]
a[4][0] a[4][1] a[4][2]

如表所示

数组的遍历,使用

1
2
3
4
for (int i = 0; i < Length; i++)
{
printf("%d ", a[i]);
}

来完成

基础部分的笔记到此结束,剩下的我想每周一个文(其实我已经看完了啦啦啦)

评论加载中