浙大版《C语言程序设计(第3版)》 - 翁恺 - 学习笔记

这是一份关于浙江大学翁恺教授的《C语言程序设计(第3版)》的学习笔记,涵盖了从变量、运算符、表达式、分支、循环到函数、数组、指针、字符串、结构体等多个核心概念的详细讲解,还包括了编程实践中的数据类型选择、内存管理、错误处理等方面的内容。笔记强调了理解计算机思维方式、变量的赋值与初始化、循环控制、函数调用及参数传递的重要性,并提供了多种编程技巧和实例解析。

2.1.1.2 计算机和编程语言:计算机的思维方式

程序的执行

  • 解释:借助一个程序,那个程序能试图理解你的程序,然后按照你的要求执行。
  • 编译:借助一个程序,就像一个翻译,把你的程序翻译成计算机真正能懂的语言——机器语言——写的程序,然后,这个机器语言写的程序就能直接执行了。

11.2.1.3 变量:变量赋值与初始化

这里写图片描述

如果变量没有初始化,就直接拿到右边去用,会出现什么呢?

这里写图片描述

得到了一个非常奇怪的结果,这是因为,在内存当中,我们有一个变量 i 我们没有给它一个初始值,那么,它正好在内存当中,在什么地方,那个地方原本有一些什么样的值在里头,它就是那个值了。

12.2.1.4 变量:变量输入

读整数

  • scanf("%d", &price);
  • 要求scanf这个函数读入下一个整数,读到的结果赋值给变量price。

scanf和printf中,f表示format格式化的意思。

13.2.1.5 变量:常量VS变量

常量(C99)

  • int change = 100 - price;
  • 固定不变的数,是常数。直接写在程序里,我们称作直接量(literal)。
  • 更好的方式,是定义一个常量:const int AMOUNT = 100
#include <stdio.h>

int main()
{
    const int AMOUNT = 100;
    int price = 0;

    printf("请输入金额(元):");
    scanf("%d", &price);

    int change = AMOUNT - price;
    printf("找您%d元。\n", change);

    return 0;
}

const(C99)

  • const是一个修饰符,加在int的前面,用来给这个变量加上一个const(不变的)的属性。这个const的属性表示这个变量的值一旦初始化,就不能再修改了。
  • int change = AMOUNT - price;
  • 如果你试图对常量做修改,把它放在赋值运算符的左边,就会被编译器发现,指出为一个错误。

14.2.1.6 变量:浮点数

这里写图片描述

这里写图片描述

这里写图片描述

%lf对应double。

这里写图片描述

16.2.2.2 表达式:运算符优先级

注意这里优先级为1的单目运算符+-

这里写图片描述

这里写图片描述

注意,a=6这个式子本身,是有结果的,也就是6。

这里写图片描述

17.2.2.3 表达式:交换变量

视频中4分20秒开始出现Dev C++断点调试的使用方法。

20.3.0.1 编程练习解析:PAT再解释

视频中5分30秒开始,出现了对scanf的讲解。

出现在scanf格式字符串里面的东西,是它一定要你输入的东西,而不是它会给你看的东西。

28.3.2.1 分支:嵌套的if-else

这里写图片描述

这里写图片描述

(学习笔记:能用大括号就用大括号,避免歧义。)

这里写图片描述

29.3.2.2 分支:级联的if-else if

这里写图片描述

30.3.2.3 分支:if-else的常见错误

这里写图片描述

这里写图片描述

31.3.2.4 分支:多路分支

这里写图片描述

这里写图片描述

这里写图片描述

(以下代码利用了switch-case的某个特性)

这里写图片描述

34.4.1.3 循环:do-while循环

这里写图片描述

(注意:while结尾要有分号)

35.4.2.1 循环应用:循环计算

这里写图片描述

(计算之前先保存原始的值,后面可能有用。)

40.5.1.2 第三种循环:循环的计算和选择

这里写图片描述

41.5.2.1 循环控制:循环控制

(判断素数)

这里写图片描述

(上面的代码中,设置一个标志位的写法,我认为值得借鉴。)

(判断素数的另一种写法。)

这里写图片描述

43.5.2.3 循环控制:从嵌套的循环中跳出

#include <stdio.h>

int main()
{
    int x;
    int one, two, five;
    int exit = 0;

    scanf("%d", &x);
    for (one=1; one<x*10; one++)
    {
        for (two=1; two<x*10/2; two++)
        {
            for (five=1; five<x*10/5; five++)
            {
                if (one + tw0*2 + five*5 == x*10)
                    {
                        printf("可以用%d个1角加%d个5角得到%d元\n",
                            one, two, five, x);
                        exit = 1;
                        break;
                    }
            }
            if (exit == 1) break;
        }
        if (exit == 1) break;
    }
}

(
我主要对这里的先设置一个标志int exit = 0;,然后满足某种条件后,改变标志exit = 1,进而改变程序控制流程的写法,感兴趣。
)

45.5.3.2 循环应用:整数分解

(这一段的视频值得重新一看,整数正序分解,因为C 语言中没有趁手的工具,所以这里实现起来略繁琐。)

46.5.3.3 循环应用:求最大公约数

辗转相除法求最大公约数

这里写图片描述

48.6.0.2 编程练习解析:编程练习解析4-1

(水仙花数编程实现,值得一看)

49.6.0.3 编程练习解析4-2:九九乘法表

50.6.0.4 编程练习解析4-3:统计素数求和

(关键词:素数、质数)

52.6.0.6 编程练习解析5-0:n项求和

每一项的分子是前一项分子与分母的和,分母是前一项的分子。

这里写图片描述

(下面的代码值得一看)

这里写图片描述

54.6.1.1 数据类型:数据类型

sizeof

  • 是一个运算符,给出某个类型或变量在内存中所占据的字节数
  • sizeof(int)
  • sizeof(i)

这里写图片描述

55.6.1.2 数据类型:整数类型

这里写图片描述

整数

  • char:1字节(8比特)
  • short:2字节
  • int:取决于编译器(CPU),通常的意义是“1个字”
  • long:取决于编译器(CPU),通常的意义是“1个字”
  • long long:8字节

这里写图片描述

当我们在说1台计算机的字长的时候,我们指的是寄存器是多少宽的,也就是说,这个寄存器是几个bit的。比如说,当我们说寄存器是32个bit的,每一个寄存器可以表达32个bit的数据,同时也是在说,CPU和RAM之间在总线上传递数据的时候,每一次的传递是32个bit,也就是说,当要从内存RAM取数据到CPU里面去,每一次就会要取32个bit。

除了32,现在更常见的是64个bit。

字长在C语言中,反映为int。int表达的是1个寄存器的大小。所以,在不同的平台、CPU上面,int会不一样大。

56.6.1.3 数据类型:整数的内部表达

这里写图片描述

这里写图片描述

这里写图片描述

所以,为什么我们要在计算机的内部使用补码呢?

最大的好处就是,如果你有了一个补码,你用补码来表示这个-1,那么,当你在做加法的时候,你不需要根据条件,去变换,把加+变成减-,你直接拿它去做普通的二进制的加法,你就会得到你想要的那个结果。

57.6.1.4 数据类型:整数的范围

整数越界

整数是以纯二进制方式进行计算的,所以:
- 11111111 + 1 –> 100000000 –> 0
- 01111111 + 1 –> 10000000 –> -128(这里我存在疑问)
- 10000000 + 1 –> 01111111 –> 127

下面的代码似乎可以解答我的疑问:

这里写图片描述

这里写图片描述

-2^(32-1) —— 2^(32-1)-1

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

(关键词:无符号数、unsigned
这整段视频建议重新细看、加强理解。)

这里写图片描述

这里写图片描述

58.6.1.5 数据类型:整数的格式化

这里写图片描述

(如下的代码,建议看视频的详细解释)

这里写图片描述

59.6.1.6 数据类型:选择整数类型

这里写图片描述

60.6.1.7 数据类型:浮点类型

这里写图片描述

(inf:正负的无穷大
nan:表示不是一个有效的数字
这段视频建议再去详细看。)

这里写图片描述

科学计数法

#include <stdio.h>

int main()
{
    double ff = 1234.56789;
    printf("%e,%f\n", ff, ff);

    return 0;
}

输出:

1234568e+03,1234.567890

这里写图片描述

#include <stdio.h>

int main()
{
    double ff = 1E-10;
    printf("%E,%f\n", ff,ff);

    return 0;
}

输出:

1.000000E-10,0.000000

这里写图片描述

这里写图片描述

61.6.1.8 数据类型:浮点的范围与精度

这里写图片描述

#include <stdio.h>

int main()
{
        printf("%f\n", 12.0/0.0);
        printf("%f\n", -12.0/0.0);
        printf("%f\n", 0.0/0.0);

        return 0;
}
$ gcc q.c
$ ./a.out
inf
-inf
-nan

这里写图片描述

这里写图片描述

62.6.1.9 数据类型:字符类型

这里写图片描述

这里写图片描述

这里写图片描述

63.6.1.10 数据类型:逃逸字符

(即转义字符)

这里写图片描述

这里写图片描述

64.6.1.11 数据类型:类型转换

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

65.6.2.1 其他运算:逻辑类型

bool

  • #include <stdio.h>
  • 之后就可以使用bool和true、false。

67.6.2.3 其他运算:条件运算与逗号运算

条件运算符

  • count = (count > 20) ? count - 10 : count + 10
  • 条件、条件满足时的值和条件不满足时的值。

69.7.1.2 函数的定义和使用:函数的定义和调用

(8分01秒开始出现了“单步进入”,讲解了调用函数时,进入函数内部、单步调试)

71.7.2.1 函数的参数和变量:函数原型

函数的先后关系

void sum(int begin, int end)
{
    int i;
    int sum = 0;
    for (i=begin; i<=end; i++)
    {
        sum += i;
    }
    printf("%d到%d的和是%的\n", begin, end, sum)
}

int main()
{
    sum(1,10);
    sum(20,30);
    sum(35,45);

    return 0;
}

像这样把sum()写在上面,是因为:

  • C的编译器自上而下顺序分析你的代码;
  • 在看到sum(1,10)的时候,它需要知道sum()的样子;
  • 也就是sum()要几个参数,每个参数的类型如何,返回什么类型。
void sum(int begin, int end);   // 声明。这里是函数原型

int main()
{
    sum(1,10);
    sum(20,30);
    sum(35,45);

    return 0;
}

void sum(int begin, int end)    // 定义。
{
    int i;
    int sum = 0;
    for (i=begin; i<=end; i++)
    {
        sum += i;
    }
    printf("%d到%d的和是%的\n", begin, end, sum)
}

这里写图片描述

72.7.2.2 函数的参数和变量:参数传递

这里写图片描述

这里写图片描述

C语言在调用函数时,只能传值给函数。

当我们在main()函数中,做swap(a,b)的时候,是把a的值5交给了swap里的a、把b的值6交给了swap里的b。swap里的a、b,与main里的a、b完全没有任何关系的。

我们在swap里面,对a、b做的任何事情,是swap里的参数a、b的事情,和main的a、b没有任何关系。如上的代码,不能交换a、b的值。

这里写图片描述

73.7.2.3 函数的参数和变量:本地变量(局部变量)

这里写图片描述

(关键词:本地变量,也叫做局部变量,因为英文是local,可翻译为本地或局部。
)

也有的地方把它叫做自动变量,把它叫做自动变量是和我们后面讲的一件事情有关系,它的生存期和作用域的关系,把它叫做自动变量是因为,它的生存期是自动的。

这里写图片描述

(这一段,建议借助视频讲解和在Dev C++编译器中断点调试,可以辅助加强理解context等概念的含义。

关键词:生存期、作用域
从1分59秒开始看。
从4分09秒开始看。)

本地变量的规则

这里写图片描述

(整段视频都值得重新仔细看,介绍了作用域、生存期,可以结合Python的LEGB同时理解。

特别是8分39秒开始的地方,依次介绍了类似嵌套作用域、变量掩盖之类的概念。)

76.8.1.2 数组:数组的使用

这里写图片描述

在内存中,数组的单元是依次排列的,而且是紧密依次排列的。

这里写图片描述

这里写图片描述

77.8.1.3 数组:数组的例子

通常来说,用到数组的程序,都需要这么一些环节。

这里写图片描述

78.8.2.1 数组运算:数组运算

这里写图片描述

(以下值得一看)

这里写图片描述

这里写图片描述

这里写图片描述

79.8.2.2 数组运算:数组例子

(判断素数、质数)

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

(求解素数的另外一种思路的算法。)

这里写图片描述

(伪代码)

这里写图片描述

80.8.2.3 数组运算:二维数组

这里写图片描述

81.9.1.1 指针:取地址运算

这里写图片描述

为什么变量会有地址?

因为 C 语言的变量,是放在内存里的。每 1 个变量,比如说 int ,可能是 4 个字节,在内存中要占一定的地方,放在某个地方,就有 1 个地址。 & 运算符就是把地址拿出来。

这里写图片描述

(整段视频都值得重新看,
特别是6分38秒开始的,
关键词:C语言的内存模型、变量的地址、内存中的堆栈stack、自顶向下、分配变量。
)

这里写图片描述

这里写图片描述

#include <stdio.h>

int main(void)
{
        int a[10];

        printf("%p\n", &a);
        printf("%p\n", a);
        printf("%p\n", &a[0]);
        printf("%p\n", &a[1]);

        return 0;
}

输出:

$ gcc q.c
$ ./a.out
0x7ffe025df0d0
0x7ffe025df0d0
0x7ffe025df0d0
0x7ffe025df0d4

这里写图片描述

82.9.1.2 指针:指针

这里写图片描述

这里写图片描述

(最后2行,p为int型指针,q为int型、不是指针。)

这里写图片描述

当我们说, p 指向了 i,实际的意思是,p 的值是变量 i 的地址。

这里写图片描述

这里写图片描述

这里写图片描述

#include <stdio.h>

void f(int *p);
void g(int k);

int main(void)
{
        int i = 6;
        printf("&i=%p\n", &i);
        f(&i);
        g(i);
        return 0;
}

void f(int *p)
{
        printf(" p=%p\n", p);
        printf("*p=%d\n", *p);
}

void g(int k)
{
        printf("k=%d\n", k);
}

输出:

$ gcc w.c
$ ./a.out
&i=0x7ffd4447a5d4
 p=0x7ffd4447a5d4
*p=6
k=6

这就意味着,通过 *p 这个指针,我们访问到了 p 所指的 int i 里面的值。

增加一行代码 *p = 26;

#include <stdio.h>

void f(int *p);
void g(int k);

int main(void)
{
        int i = 6;
        printf("&i=%p\n", &i);
        f(&i);
        g(i);
        return 0;
}

void f(int *p)
{
        printf(" p=%p\n", p);
        printf("*p=%d\n", *p);
        *p = 26;
}

void g(int k)
{
        printf("k=%d\n", k);
}

输出:

$ gcc w.c
$ ./a.out
&i=0x7ffd8ecfb624
 p=0x7ffd8ecfb624
*p=6
k=26

k=26 意味着,在经历了 f 函数的调用了之后, i 的值被改了。

地址值 &i 被传进了函数 f(int *p),这里,仍然是值的传递,因为传进来的是地址,所以,通过这个地址,在函数内部,可以以这种方式,访问到外面的 i 变量。

因为 p 的值,就是 i 的地址。 *p 就代表了 i 。

当我们做 *p = 26 这个运算的时候,我们实际做的事情,是对 i 做的。

这里写图片描述

这里写图片描述

83.9.1.3 指针:指针的使用

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

84.9.1.4 指针:指针与数组

这里写图片描述

(函数参数里的数组是指针。
从视频0分59秒开始看起)

这里写图片描述

这里写图片描述

(“*arar[]在函数参数表中出现,是等价的”)

这里写图片描述

这里写图片描述

这里写图片描述

(const 常量)

这里写图片描述

85.9.1.5 指针:指针与const

这里写图片描述

这里写图片描述

上图。如果指针是const,比如int * const q = &i;,在这种情况下,q这个指针是const,它的意思是说,q的值不能被改变,什么是q的值?就是i的地址,就是q指向了i这个事实不能被改变,也就是q不能再指向别人了,它们之间的关系是永久的。

这里写图片描述

这里写图片描述

(对上图和上上图的一点说明:)
p可以指向别人,i可以被赋以别的值,但是通过p去修改i就不可以。

这里写图片描述

如果const在*前面,那么,表示它所指的东西不能被修改;
如果const在*后面,那么,表示指针不能被修改;

这里写图片描述

这里写图片描述

这里写图片描述

86.9.2.1 指针运算:指针运算

这里写图片描述

当我们给一个指针加1的时候,它不是在地址值上加1,它在地址值上加一个sizeof(那个指针所指的类型)

这里写图片描述

所以对指针做一个加1的动作,意味着,我们要把它移到下一个单元去。

这里写图片描述

这里写图片描述

(当做两个指针相减的时候,它给你的是两个地址的差除以sizeof(它的类型),也就是,在这两个地址之间,有几个这样类型的东西在,或者说,能放几个这样类型的东西。)

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

87.9.2.2 指针运算:动态内存分配

这里写图片描述

(0分52秒开始,略为完整地介绍了动态内存分配malloc、内存释放free()。

第12行:
malloc返回的结果是是void *,而a是int*,所以我们还要类型转换一下。(在前面加上(int*))。
)

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

(第8行:每次申请100兆的空间,然后把申请到的空间,交给p,(p=malloc(100*1024*1024))中,对p做了一个赋值。赋值也是个表达式,有个结果,结果就是p得到的malloc的那个结果。

while ( (p=malloc(100*1024*1024)) ){
    cnt++;
}

这样的代码同时做了2件事情:
1.把malloc的结果赋给了p这个变量;
2.要让p得到的这个值,拿来做while的条件。

如果p得到的地址不是0,那就意味着它得到了一个有效的地址,那么,我们循环要继续,要让cnt去加加。
如果它得到的地址是0,那么while就要退出来。
)

这里写图片描述

(着重:首地址)

这里写图片描述

88.10.1.1 字符串:字符串

(在字符数组的最后一个元素,使用'\0')

这里写图片描述

这里写图片描述

这里写图片描述

89.10.1.2 字符串:字符串变量

这里写图片描述

(0分28秒开始。
关键词:程序的代码段、只读、保护机制。)

这里写图片描述

这里写图片描述

这里写图片描述

90.10.1.3 字符串:字符串的输入输出

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

91.10.1.4 字符串:字符串数组,以及程序参数

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

92.10.2.1 字符串函数:单字符输入输出

这里写图片描述

这里写图片描述

93.10.2.3 字符串函数: 字符串函数 strlen

这里写图片描述

这里写图片描述

(作为参数,数组的形式和指针的形式是一样的,因为,数组传进去,也是指针,所以,我们在这里全部用指针的形式来表达了。)

size_t strlen(const char *s)的参数中,const char *s的前面有 1 个const,含义是,希望函数strlen()不修改传进去数组char *s

94.10.2.3 字符串函数:字符串函数strcmp

这里写图片描述

(4分01秒开始,对strcmp的重新实现,值得一看。
包括数组实现和指针实现。
)

95.10.2.4 字符串函数: 字符串函数 strcpy

这里写图片描述

这里写图片描述

这里写图片描述

(5分20秒开始,分析并重新实现了strcpy,有数组、指针版本。)

96.10.2.5 字符串函数strcat

这里写图片描述

这里写图片描述

这里写图片描述

97.10.2.6 字符串函数:字符串搜索函数

这里写图片描述

这里写图片描述

98.11.1.1 枚举:枚举

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

99.11.2.1 结构:结构类型

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

(上 面的代码中,main函数外的struct date { sth. }是在声明一种新的结构类型,main函数内的struct date today = sth.是在定义这种结构类型的一个结构变量。
)

这里写图片描述

这里写图片描述

这里写图片描述

(数组变量的名字,就是数组的地址。)

100.11.2.2 结构:结构:结构与函数

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

101.11.2.3 结构:结构中的结构

(结构数组)

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

102.11.3.1 联合:类型定义

这里写图片描述

这里写图片描述

(上面,Date是别名。)

这里写图片描述

这里写图片描述

103.11.3.2 联合: 联合

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

104.12.1.1 全局变量:全局变量

这里写图片描述

这里写图片描述

这里写图片描述

105.12.1.2 全局变量: 静态本地变量

这里写图片描述

#include <stdio.h>

int f(void);

int gAll = 12;

int main(int argc, char const *argv[])
{
        f();
        f();
        f();
        return 0;
}

int f(void)
{
        static int all = 1;
        printf("in %s all=%d\n", __func__, all);
        all += 2;
        printf("agn in %s all=%d\n", __func__, all);
        return all;
}

输出:

$ gcc q.c
$ ./a.out
in f all=1
agn in f all=3
in f all=3
agn in f all=5
in f all=5
agn in f all=7

(
个人理解:

这里的 静态本地变量 ,让我联想起了 Python 中的 生成器yield

有时间一定要去读 《 Python 源码分析》,了解下生成器的内部实现。
)

这里写图片描述

106.12.1.3 全局变量: 后记

这里写图片描述

  • 返回本地变量的地址是危险的

如果有 1 个函数,你要让它返回 1 个指针,那么,你如果返回的是本地变量的地址,这是危险的。
因为一旦离开这个函数,本地变量就不存在了。

#include <stdio.h>

int* f(void);
void g(void);

int main(int argc, char const *argv[])
{
        int *p = f();
        printf("*p=%d\n", *p);
        g();
        printf("*p=%d\n", *p);

        return 0;
}

int* f(void)
{
        int i=12;
        return &i;
}

void g(void)
{
        int k = 24;
        printf("k=%d\n", k);
}

我的输出:

$ gcc q.c
q.c: In function ‘f’:
q.c:19:9: warning: function returns address of local variable [-Wreturn-local-addr]
  return &i;
         ^
$ ./a.out
Segmentation fault (core dumped)

视频中的输出:

。。。
1 warning generated.
*p=12
k=24
*p=24

*p 又变成 24 了,但这个过程中,没有人对 *pi 做任何事情,但是 p 所指的那个地方却变成了 24 了。

你可以自己改一点这里的程序,如果在 f 函数里打印出 i 的地址,在 g 函数里打印出 k 的地址,你会发现它们是一样的。

返回 1 个本地变量的地址,让外面的程序继续使用它是有风险的。因为这个函数结束以后,那个本地变量的地址会被继续分配给别人去使用的。

  • 返回全局变量或静态本地变量的地址是安全的

因为,全局变量或静态本地变量的地址和函数没关系,它们是全局生存期的。

  • 返回在函数内 malloc 的内存是安全的,但是容易造成问题

  • 最好的做法是返回传入的指针

这里写图片描述

107.12.2.1 编译预处理和宏: 宏定义

这里写图片描述

这里写图片描述

#include <stdio.h>

#define PI 3.14159
#define FORMAT "%f\n"
#define PI2 2*PI // pi * 2
#define PRT printf("%f ", PI); \
            printf("%f\n", PI2)

int main(int argc, char const *argv[])
{
        printf(FORMAT, PI2*3.0);
        PRT;
        return 0;
}

输出:

$ gcc q.c
$ ./a.out
18.849540
3.141590 6.283180

这里写图片描述

这里写图片描述

108.12.2.2 编译预处理和宏: 带参数的宏

像函数的宏

  • #define cube(x) ((x)*(x)*(x))
  • 宏可以带参数

这里写图片描述

这里写图片描述

这里写图片描述

宏定义的结尾不要加上分号 ;

这里写图片描述

这里写图片描述

109.12.3.1 大程序结构: 多个源代码文件

这里写图片描述

这里写图片描述

这里写图片描述

110.12.3.2 大程序文件: 头文件

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

111.12.3.3 大程序结构: 声明

这里写图片描述

  • 定义时产生代码的东西

比如说函数、全局变量。

这里写图片描述

在头文件中方的不是声明,而是定义,会造成问题。

这里写图片描述

这里写图片描述

这里写图片描述

112.13.1.1 文件: 格式化输入输出

这里写图片描述

这里写图片描述

#include <stdio.h>

int main(int argc, char const *argv[])
{
        printf("%9d\n", 123);
        printf("%-9d\n", 123);
        printf("%+9d\n", 123);
        printf("%+-9d\n", 123);
        printf("%-+9d\n", 123);
        printf("%-+9d\n", -123);
        printf("%-9d\n", -123);
        printf("%09d\n", 123);

        return 0;
}

输出:

#include <stdio.h>

int main(int argc, char const *argv[])
{
        printf("%9d\n", 123);
        printf("%-9d\n", 123);
        printf("%+9d\n", 123);
        printf("%+-9d\n", 123);
        printf("%-+9d\n", 123);
        printf("%-+9d\n", -123);
        printf("%-9d\n", -123);
        printf("%09d\n", 123);

        return 0;
}

这里写图片描述

#include <stdio.h>

int main(int argc, char const *argv[])
{
        printf("%9.2f\n", 123.0);

        return 0;
}

输出:

$ gcc q.c
$ ./a.out
   123.00

printf("%9.2f\n", 123.0);中,9.2f的含义是,输出 1 个浮点数,后面是 2 位小数,前面的空位、整数位、小数点位加上小数位,一共是 9 位。

#include <stdio.h>

int main(int argc, char const *argv[])
{
        printf("%*d\n", 6, 123);

        return 0;
}

输出:

$ gcc q.c
$ ./a.out
   123

printf("%*d\n", 6, 123);* 意思是, 6 是用来满足这个 * 的, 6 会被填到 * 里面去; 123 是用来满足这个 d 的。

所以,输出包括前面的 3 个空格加后面的 3 位数,总共占据 6 个位置。

这里写图片描述

这里写图片描述

#include <stdio.h>

int main(int argc, char const *argv[])
{
        int num;
        printf("%drf%n\n", 12345, &num);
        printf("%d\n", num);

        return 0;
}

输出:

$ gcc q.c
$ ./a.out
12345rf
7

printf("%drf%n\n", 12345, &num);中, %n 的含义是,当 printf 执行到这个地方的时候,已经输出了多少个字符,然后填到 &num 指针所指的那个变量里面去。

这里写图片描述

#include <stdio.h>

int main(int argc, char const *argv[])
{
        int num;
        scanf("%*d%d", &num);
        printf("%d\n", num);
        return 0;
}

输出:

$ gcc q.c -o test
$ ./test
123 345
345

说明:把前面的 123 跳过,然后读到了 345 。 * 的意思是跳过。

这里写图片描述

#include <stdio.h>

int main(int argc, char const *argv[])
{
        int num;
        scanf("%i", &num);
        printf("%d\n", num);
        return 0;
}

输出:

$ gcc q.c -o test
$ ./test
123
123
$ ./test
0x12
18
$ ./test
012
10

这里写图片描述

113.13.1.2 文件: 文件输入输出

这里写图片描述

$ gcc q.c -o test
$ ./test
12345
12345
$ ./test > 12.out
12345
$ cat 12.out
12345
$ cat > 12.in
12345(备注:这里可能需要输入 Ctrl + D 终止。)
$ cat 12.in
12345
$ ./test < 12.in
12345
$ ./test < 12.in > 12.out
$ cat 12.out
12345

这是叫做程序运行时的重定向。

这里写图片描述

这里写图片描述

#include <stdio.h>

int main(int argc, char const *argv[])
{
        FILE *fp = fopen("12.in", "r");
        if ( fp ) {
                int num;
                fscanf(fp, "%d", &num);
                printf("%d\n", num);
                fclose(fp);
        } else {
                printf("无法打开文件\n");
        }

        return 0;
}
$ gcc q.c -o test
$ ./test
12345
$ rm 12.in
$ ./test
无法打开文件

这里写图片描述

114.13.1.3 文件: 二进制文件

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

(视频中,这里有一段代码,建议看视频。)

这里写图片描述

这里写图片描述

115.13.2.1 位运算: 按位运算

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

(视频中,有代码,建议看视频。)

这里写图片描述

这里写图片描述

对 1 个数,做 2 次异或,就翻回去了。

这里写图片描述

116.13.2.2 位运算:移位运算

这里写图片描述

这里写图片描述

117.13.2.3 位运算:位运算例子

这里写图片描述

118.13.2.4 位运算: 位段

这里写图片描述

这里写图片描述

119.14.1.1 可变数组: 可变数组

这里写图片描述

这里写图片描述

这里写图片描述

120.14.1.2 可变数组:可变数组的数据访问

121.14.1.3 可变数组:可变数组的自动增长

122.14.2.1 链表:可变数组的缺陷

123.14.2.2 链表: 链表

这里写图片描述

#include _NODE_H_
#define _NODE_H_

typedef struct _node {
    int value;
    struct _node *next;
} Node;

# endif

124.14.2.3 链表:链表的函数

125.14.2.4 链表:链表的搜索

126.14.2.5 链表:链表的删除

这里写图片描述

这里写图片描述

127.14.2.6 链表:链表的清除

这里写图片描述


断点调试

Dev C++的断点调试

参考文献:
1. C语言 - 翁恺 - 浙江大学。

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值