📝 我的笔记

还没有笔记

选中页面文字后点击「高亮」按钮添加

1 C语言基础:

📜 原文
📖 逐步解释
∑ 公式拆解
💡 数值示例
⚠️ 易错点
📝 总结
🎯 存在目的
🧠 直觉心智模型
💭 直观想象

1C语言基础:

2数据类型、位运算

COMS W3157
Dr. Borowski

3鉴于你已经了解Java

C语言的语法与Java有一些相似之处

学习C语言就像学习机器的真正工作方式。

Java隐藏细节,而C语言则对程序的运作方式提供完全控制。

4显著差异:

C语言是过程式语言,而非面向对象语言。

在C语言中,内存管理是程序员的工作。

5第一个C程序

```

/* Every C program needs an entry point -- the main

function */

// Function return type, name, arguments

int main(int argc, char **argv) {

return 0; // Every statement ends with ";"

}

```

上述程序的输出是什么?

6第一个C程序

```

/* Every C program needs an entry point -- the main

function */

// Function return type, name, arguments

int main(int argc, char **argv) {

return 0; // Every statement ends with ";"

}

```

上述程序的输出是什么?

没有输出。

7第一个C程序

```

/* Every C program needs an entry point -- the main

function */

// Function return type, name, arguments

int main(int argc, char **argv) {

printf("Hello, world!\n"); // a simple print statement

// very similar to printing in Java

return 0;

}

```

上述程序的输出是什么?

8第一个C程序

```

/* Every C program needs an entry point -- the main

function */

// Function return type, name, arguments

int main(int argc, char **argv) {

printf("Hello, world!\n"); // a simple print statement

// very similar to printing in Java

return 0;

}

```

上述程序的输出是什么?

Hello, world!

9第一个C程序

```

/* Every C program needs an entry point -- the main

function */

// Function return type, name, arguments

int main(int argc, char **argv) {

return 0;

printf("Hello World!\n");

}

```

上述程序的输出是什么?

提示:思考一下这页幻灯片与上一页有什么不同。

10第一个C程序

/ 每个C程序都需要一个入口点——main函数 /

// 函数返回类型、名称、参数

int main(int argc, char **argv) { return 0; printf("Hello World! \n"); } 没有输出;return 语句在 printf 语句之前!

上述程序的输出是什么?

提示:思考一下这页幻灯片与上一页有什么不同。

11声明/定义变量

```

int main(int argc, char **argv) {

// declare variable: type name (with letters, digits, "_")

char var0;

// first character should be alphabet or underscore

int var_1;

// variable names are case sensitive

float Var_1;

var0 = '0'; // assignment statement

return 0;

}

```

12基本类型

与Java一样,C语言定义了 charshortintlong 类型,但它也包括 long long

C语言还具有 floatdouble 类型——带浮点精度的数字。

一般来说,可以保证:

char <= short <= int <= long <= long long

在我们的Linux系统上:

| char: | 1 | byte | long: |

| :--- | :--- | :--- | :--- |

| short: | 2 | 8 bytes | |

| int: | 4 | bytes | long long: |

| float: | 4 bytes | double: | 8 bytes |

13有符号 vs. 无符号

整型可以声明为 unsigned。例如,int x; 创建一个取值范围在 $\left[-2^{31}, 2^{31}-1\right]$ 的变量,而 unsigned int x; 创建一个取值范围在 $\left[0,2^{32}-1\right]$ 的变量。

我们使用二进制补码表示来存储有符号变量。

二进制加法

| 0 | 0 | 1 | 1 | |

| ---: | ---: | ---: | ---: | ---: |

| +0 | +1 | +0 | +1 | |

| -- | --- | --- | --- | |

| 0 | 1 | 1 | 10 | | | $1+1=0$,但 |

| :--- |

| 你需要 |

| 进位1, |

| 因为 $10_{2}=2_{10}$。 |

14二进制加法练习

1011

$+\quad 1011$

------

?

15二进制加法练习

$$ \begin{array}{r} 1 \\ 1011 \\ +1011 \\ ------ \end{array} $$

$$ 0 $$

16二进制加法练习

$$ \begin{array}{r} 11 \\ 1011 \\ +\quad 1011 \\ ----- \\ 10 \end{array} $$

17二进制加法练习

$$ \begin{array}{r} 11 \\ 1011 \\ +\quad 1011 \\ ----- \\ 110 \end{array} $$

18二进制加法练习

111

1011

+ 1011

------

0110

19二进制加法练习

111

1011

+ 1011

------

10110

20二进制补码

假设我们有一个有符号 char,如下:

char c = -5;

值 -5 是如何存储在 8 位中的?

  1. 从 8 位中的正 5 开始 -> 00000101
  2. 翻转所有位。0变为1,1变为0。

00000101 -> 11111010

  1. 加 1:

$$ \begin{array}{r} 11111010 \\ + \\ ------------- \end{array} $$

11111011 <- 这就是有符号 char 中的 -5。

21二进制补码

假设我们有一个有符号 char,如下:

char c = -1;

值 -1 是如何存储在 8 位中的?

  1. 从 8 位中的正 1 开始 -> 00000001
  2. 翻转所有位。0变为1,1变为0。

00000001 -> 11111110

  1. 加 1:

$$ \begin{array}{r} 11111110 \\ + \\ ------------- \end{array} $$

11111111 <- 这就是有符号 char 中的 -1。

22二进制补码 - 逆运算

假设你有一个二进制数 11101111,并且你知道它被存储为一个(有符号)char。它是哪个数字?

最左边的位是符号位。1表示负数,0表示非负数。

因为它是一个负数,所以再遵循相同的 3 步过程。

23二进制补码 - 逆运算

  1. 从 8 位中的数字开始 -> 11101111
  2. 翻转所有位。0变为1,1变为0。11101111 -> 00010000
  3. 加 1:

11101111 等价于 -00010001,或者说 -17。

24相等和关系运算符

表达式可以包含运算符运算符对一个或多个操作数执行操作。

相等关系运算符二元运算符,这意味着它们需要两个操作数

25逻辑运算符

&& - 逻辑与

|| - 逻辑或

! - 逻辑非

逻辑运算符只考虑它们的操作数是零还是非零。

逻辑与和逻辑或也被称为短路运算符。如果表达式的最终结果仅通过评估第一个操作数就能确定,那么第二个操作数就永远不会被评估。

26短路操作

| P | Q | $\mathrm{P} \& \& \mathrm{Q}$ |

| :---: | :---: | :---: |

| T | T | T |

| T | F | F |

| F | T | F |

| F | F | F |

当 P 为假时,整个表达式自动为假。

| P | Q | P | I |

| :---: | :---: | :---: | :---: |

| T | T | Q | |

| T | F | T | |

| F | T | T | |

| F | F | F | |

当 P 为真时,整个表达式自动为真。

27位运算符

& - 位与

| - 位或

~ - 位非

^ - 位异或

位运算符在数据的二进制表示中的位上工作。

对于接下来的几页幻灯片,请考虑以下代码:

char a = 11; // 00001011 in binary

char b = 5; // 00000101 in binary

28位与 (`&`)

$$ \begin{aligned} 00001011 / / & =\mathrm{a}(11) \\ \varepsilon 00000101 / / & =\mathrm{b}(5) \\ -00000001 / / & =\mathrm{a} \& \mathrm{~b} \end{aligned} $$

为什么有用:

29位或 (`|`)

$$ \begin{array}{r} 00001011 / /=\mathrm{a} \quad (11) \\ 100000101 / /=\mathrm{b} \quad (5) \\ -------- \\ 00001111 / /=\mathrm{a} \quad \mathrm{~b} \quad (15) \end{array} $$

为什么有用:在不改变其他位的情况下,打开(设置)值中的特定位。

30位非 (`~`)

$$ \begin{aligned} & \sim 00001011 / /=\mathrm{a}(11) \\ & -------- \\ & 11110100 / /=\sim \mathrm{a}(-12) \end{aligned} $$

为什么有用:当你需要位逆或翻转每个位时非常有用。

31位异或 (`^`)

$$ \begin{gathered} 00001011 / /=\mathrm{a}(11) \\ 00000101 / /=\mathrm{b}(5) \\ --------- \\ 00001110 / /=\mathrm{a} \wedge \mathrm{~b}(14) \end{gathered} $$

为什么有用:翻转位或检测差异——甚至可以用于在没有临时变量的情况下交换两个值。

32使用位异或 (`^`) 进行交换

如果使用位异或交换2个变量,我们不需要临时变量。假设 a=11b=5

$$ \begin{array}{l|l|} a=a \wedge b ; & 00001011 \wedge 00000101=00001110 \\ \hline a=(11) \wedge & \wedge \\ b=a \wedge b ; & 00001110 \wedge 00000101=00001011 \\ b=(14) \wedge & (5) \\ b= & (11) \\ a & =a \wedge b ; \\ a=(14) \quad \wedge \quad (11) & = \\ a & =(5) \\ \hline \text { 最终值: } a=5, b=11 . \text { 交换成功! } \end{array} $$

33位移运算符

这些运算符允许我们将位向左或向右“移动”。

a = a << 1;

34位移运算符

这些运算符允许我们将位向左或向右“移动”。

$$ a=a \ll \frac{1}{1} ; $$

$$ \begin{aligned} & 00001011 / /=\mathrm{a}(11) \\ & \ll \\ & -------- \\ & 00010110 / /=(22) \end{aligned} $$

$$ \begin{gathered} \ll 1= \\ \text { 乘以 } 2^{1} \end{gathered} $$

这个操作数决定了所有位向左移动的位数。

35位移运算符

这些运算符允许我们将位向左或向右“移动”。

a = a << 1;

$$ \begin{aligned} & 00001011 / /=a(11) \\ & \ll \\ & -001 \\ & 00010110 / /=(22) \end{aligned} $$

乘以 $2^{1}$

36位移运算符

这些运算符允许我们将位向左或向右“移动”。

a = a << 1;

$$ \begin{aligned} & 00001011 / /=a(11) \\ & \ll \\ & -001 \\ & 00010110 / /=(22) \end{aligned} $$

乘以 $2^{1}$

$$ a=\left.a \gg\right|_{\lambda} ^{2} ; $$

这个操作数决定了所有位向右移动的位数。

00001011 // = a (11)

>> 2

---------

$$ 00000010 / /=(2) $$

>> 2 =

int division by $2^{2}$

37字面量

| 字面量类型 | 字面量示例 | C语言中的变量定义示例 |

| :--- | :--- | :--- |

| 十进制 | 85 | int dec = 85; |

| 八进制 | 0213 | int oct = 0213; |

| 十六进制 | 0x4b | int hex = 0x4b; |

| int | 30 | int a = 30; |

| unsigned int | 30u | unsigned int ua = 30; |

| long | 30l | long b = 30; |

| unsigned long | 30ul | unsigned long ub = 30; |

| double | 3.14159 | double d = 3.14159; |

| | 314159e-5L | double sd = 314159e-5L; |

| float | 210.5f | float f = 210.5f; |

| char | 'c' | char c = 'c'; |

| string (char ) | "abcd" | char s = "abcd"; |

要声明八进制数,我们必须以 0 开头;否则,编译器会认为它是一个十进制数。

38命令行参数

我们可以使用 argcargv 遍历命令行参数。

```

#include

int main(int argc, char *argv[]) {

```

我们将在下节课深入探讨!

```

for (int i = 0; i < argc; i++) {

printf("Argument %d: %s\n", i, argv[i]);

}

}

```

```

Example Run: ./program apple banana

Output: Argument 0: ./program

Argument 1: apple

Argument 2: banana

```

39`atoi()`

atoi 允许你将字符串转换为整数。

```

#include

#include // Needed for atoi.

int main() {

char str[] = "42";

int num = atoi(str);

printf("The number is %d\n", num);

return 0;

}

```

将字符串 "42" 转换为整数 42。

40`printf()`

printf 允许你打印格式化字符串。

```

#include

int main() {

int var1 = 15;

double var2 = 0.179;

printf("var1 is %d and var2 is %lf\n", var1, var2);

return 0;

}

```

var1 is 15 and var2 is 0.179000 打印到标准输出。

成功返回时,printf 返回打印的字节数(不包括用于结束字符串输出的空字节),失败时返回负数。

41`scanf()`

scanf 允许你扫描(读取)格式化的用户输入。

```

#include

int main() {

int age;

printf("Enter your age: ");

scanf("%d", &age);

R

printf("You entered %d\n", age);

return 0;

}

```

从标准输入读取并将值存储到 age 中。

42`putc()`

putc 允许你向文件或输出流写入1个字符。

```

#include

int main() {

char ch = 'A';

putc(ch, stdout);

return 0;

}

```

将字符 A 打印到标准输出。