海贼19-8班现场课
9262人加入学习
(1人评价)
C语言程序设计(海贼现场课)
价格 ¥ 600.00
该课程属于 海贼19-8班(C++高薪班) 请加入后再学习

总结:

头文件,相当于对要用到的所有函数进行集体声明;

把且仅把函数声明,放进头文件当中;

把函数定义,放进.c/.cpp文件当中;

这种编写配合习惯:对于不同人调用函数编写代码,避免出现有关函数声明与定义上的错误,排查函数错误,这三类工作都有帮助;

<stdio.h>, "2FuncA.h", "3FuncB.h", "4Func.h"

[展开全文]

总结:

关于函数定义和声明有三类错误:

    1、未声明函数;语法错误,在编译阶段报错

    2、未定义函数;

    3、重定义函数;(编译阶段和链接阶段都会报错)

源文件如何被计算机一步步处理?

Step 1:预编译——宏定义,将文件内的别名和缩写进行替换;并将include的文件内容原封不动地粘贴进来。

Step 2:编译——源文件经过预编译和编译过程,变成对象文件(.o/.obj)——这期间主要检查语法错误,例如函数未声明

Step 3:链接——对象文件经过链接,变为可执行文件(.out)——这期间会报:函数未定义或重定义错误,未定义使得计算机不知道如何实现这个函数,重定义使得计算机不知道执行哪一个函数定义;都执行就是可能世界语义了,会生成多个由不同语义函数组合而成的结果;由此可知函数定义放在哪个文件不太重要,对象文件链接的时候有就行。

[展开全文]

总结:

程序就是算法+数据结构;

算法就是,聪明人的做事方法;(因为这样做事情,高效)

if else如果都接单语句,可以用冒号表达式;

数据结构,等于结构定义加结构操作;

 

[展开全文]

总结:

用va_list, va_start, va_arg, va_end来声明,定位,获取下一个,结束来定义一个可变参数列表。

 

对于scanf和printf这样一个参数列表是可变的函数,该如何去定义?

实现可变参函数max_int,从若干个传入的参数中返回最大值。

int max_int(int a, ...);

 

如何获得a往后的参数列表?va_list 类型的变量

如何定位a后面第一个参数的位置?va_start 函数

如何获取下一个可变参数列表中的参数?va_arg 函数

如何结束整个获取可变参数列表的动作? va_end 函数

 

//先弄一个va_list类型的变量;

//然后,用va_start定位第一个参数的位置

//然后,不断用va_arg来获取下一个参数

//最后,用va_end结束整个可变参数列表的获取动作

[展开全文]

总结

如果不满足什么条件,就直接看下一个n,可以用《if... continue;》这样一种有趣的写法,称为对偶缩进;

它相对于《if...else...》 少写一个判断语句;

例如写一些特定序列的遍历算法(二分查找,三分查找及其他遍历方式),用函数指针会非常方便。

相当于定义了一个函数:算法名称(特定的函数序列,查找范围值)

 

int main() {

    int n = 286; 

    for ( ; ; n++) {

        if (binary_search(Hexagonal, Triangle(n) == -1)) continue;

//对偶缩进的写法

//“当35行成立的时候”,“当xx行成立的时候”这种表达,利于分析代码;

        if (binary_search(Pentagonal, Triangle(n) == -1)) continue;

        printf("%d\n", Triangle(n));

        break;

    }

    return 0;

}

[展开全文]

总结:

函数指针,可以用于定义一个分段函数!

 

int g(int (*f1)(int), int (*f2)(int), int (*f3)(int), int x) {

    if (x <0) {

        return f1(x);

    }

    if (x<100) {

        return f2(x);

    }

    return f3(x);

}

printf("%d\n", g(fac1, fac2, fac3, n))

//g就是一个分段函数,其中fac1,fac2,fac3为分段函数对应的不同段的函数,n为传进去需要处理的整型变量;

int (*f1)(int),代表的也是参数列表的变量,代表传进来一个函数;

传参的时候,不仅可以传一个整形,浮点型,还可以传一个函数

 

int 代表返回值的类型;

*f1,把某个函数当成一个变量传进来,放进一个函数变量当中

后面的( )里面只需要写函数参数类型即可;

 

这个足够重要,足够复杂。

 

一个新的概念产生,它是去解决一类问题的。

函数指针方便去解决类似于分段函数的函数调用;

函数指针可以用于定义一个分段函数!

[展开全文]

总结:

用函数封装的程序,有更好地易读性,查错效率会有指数级增长。

递归和递推不一样,递推是一种算法;递归是一种编程技巧,解题方式;

while ( ~scanf("%d", &n))   也可以实现一个循环读入的功能

EOF等于读入-1,而 -1 的二进制表示全都是1,按位取反全都是0,0表示条件不成立,相当于读到了EOF,文本末尾;

有两个区域可以开空间:一个叫做栈区,一个叫做堆区;

系统在分配的时候,栈区占8MB的字节,大约200万个整型int;而堆区和内存有关系,内存16G就可以开很大很大。

在定义函数的时候,占用的就是栈区。

在函数里面调用自己的时候,如果没有合适的出口,调用自己的时候,会不断开辟新的变量。

[展开全文]

打印一个数字的位数,printf(printf())

 

n /= 10,表示n在十进制的表示下,去掉一位;

n /= 2,表示n在二进制的表示下,去掉一位;

do while 和while的核心区别,do while至少执行一次!第一次不判断直接执行;

[展开全文]

总结:

条件表达式的“乘法口诀”

如果a不等于b——if  (a - b) 

如果a不等于0——if (a)

如果a等于0——if (!a)

if  (a - b) ——如果a不等于b

if (a)——如果a不等于0

if (!a)——如果a等于0

 

短路运算:(因为前半部分已经判断完了,后半部分不影响整体表达式的结果,因此不执行了,效率优先)

False &&(这部分不执行)

Ture || (这部分不执行)

i && ......

相当于

i == 0 || ......

 

 

int a = 0, b =0;

(a++) && (b++);  //该值为0,因为逻辑与先对a和b进行逻辑运算,然后,a和b再进行++的自增加1的运算。

 

求val模2的值,可以写为(val & 1)

 

计算奇数个数(或者偶数个数)的计数器,可以这么写:

count += val & 1;//表示,如果为奇数,则count加1;否则加0;

 

任务:打印0 - 9,每个数字有一个空格, 最后没有空格:(需要处理的地方在于:前后的空格如何去掉)

如果i是0,则不执行后面的语句;否则执行;

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

    i && printf(" ");                        //短路运算原则,这么写比if else更加高效!

    printf("%d", i);

}

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

    if (i) printf(" ");

    printf("%d", i);

}

[展开全文]

总结:

for括号里的第三部分,是在代码块以后操作!

for比while更加灵活。

 

船长们相比于while,更愿意用for语句,可以写出花一样的代码,它里面的条件有三部分:

for (初始化;循环条件;执行后操作){

    代码块;

}

Step 1:初始化;

Step 2:循环条件判断;

Step 3:执行代码块;

Step 4:执行后操作;

Step 5:跳转到Step 2;

 

注意,这里“执行后操作”第三部分,是代码块以后操作,而非代码块之前操作!!!!

[展开全文]

总结:

可以用Linux内核中的宏定义,来帮助CPU提前做条件分支预测,提高效率;

尽可能减少if else,条件分支判断会拖延CPU并行处理语句的效率。

取指令,指令预解析,取数据,执行,写回

 

 

【为什么CPU讨厌if语句?】

CPU会并行处理数据,如果遇到条件分支,那是做if条件里面的还是if条件外面的?

如果执行if里面的,赌错了,那么就全是无用功了,就变成串行了;

 

 

Linux内核里,写了这样一些宏定义:

#define likely(x)  __builtin_expect(!!(x), 1)

#define unlikely(x) __builtin_expect(!!(x), 0)

 

// likely 代表 x 经常成立

// unlikely 代表 x 不经常成立

 

这两行的区别,是给CPU看的。

F:取指令

D1:指令预解析

D2:取数据

EX:执行;(execute)

WB:写回;

[展开全文]

条件分支判断总结:

写switch的时候,一定要注意灵活运用break!!

!!(x)是归一化的作用,负数也为非0值;

if (!n) 表示 if (n == 0)

 

表达式:可以是逻辑判断的表达式(a == b),也可以是数学计算的表达式(a + b);

[展开全文]

2022/10/18 8:51

从86题,讲到102题

都刷过了,跳过。

虽然用的是C++,但是如果没有那个语句是C实现不了的功能,那没差别。

 

#include <stdio.h>

 

int main(){

    int a = 7, b = 3, c = 2, d = 3, e = 4;

    int *p = &a;

    --*p;

    printf("%d\n", a);

    c = a ^ b;

    printf("c = %d\n", a ^ b);

    printf("a = %d\n", b ^ c);

    printf("b = %d\n", a ^ c);

    return 0;

}

 

output:

6

c = 5

a = 6

b = 3

 

这段代码,可以非常好地告诉我们,指针是什么意思。

*p,表示a变量的值,因此可以--*p;

由于原来a为7,--a = --*p = 7-1 = 6

[展开全文]

如果n的二进制第一个位置上是1,则给p加一个小括号;

第二个位置上是1,则给p加一个中括号;

第三个位置上是1,则给p加一个大括号;

[展开全文]

 stdin:标准输入

stdout:标准输出

stderro:标准错误输出

 

当代码出bug了,stderr可以将标准输出和错误输出区分开来。

既然,标准输出,和标准错误输出,都可以重定向到文件中

那么如果,想看文件是否有bug,可以看,标准错误输出文件里面,是否有内容,这样就可以大大减少。。。的工作量。

 

不知道减少的是什么工作量;

似乎就是在编译的时候,如果有问题,就用标准错误输出,将文件写进标准错误输出文件里;

没有问题,就写进标准文件里;

这样,检查代码是否有问题,只需要看标准错误输出文件里有没有内容就可以了。

[展开全文]

sscanf:把字符串里的内容,存到a里面去;

+4,+8,就是指从第几位开始读起;

由于,字符串str代表的就是字符串的首地址

而每个指针都可以看作一个数组,因此可以+4,+8.

 

getchar(),从输入缓冲区拿走一个字符

但没有说存放在什么地方;

那么,它的作用,很用可能就是,拿走回车,保证在输入数据的时候不是按了回车,就执行程序,而是可以多输入几行数据。

[展开全文]

这里是看,printf,sprintf, fprintf三个的具体功能区别吗?

而且,这里似乎,新建立了一个文件,叫做fout。

总之,有一个文件函数操作,是超出我目前的知识的。

盲猜,大概是打开一个名为null的文件,如果没有这个文件则新建一个名为null的文件,并且在里面写w?

 

w

打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。

 

那么这个程序就是,定义了了一个长度为100的字符串,还用只写模式定义了一个文件fout

(这个定义方式,看起来很像定义了一个指向文件的指针,因为fout前面有一个*号)

 

然后输入内容以后

分别打印了:

成功打印的字符个数;

成功打印的字符串个数;

成功打印的“文件个数”?

 

 

[展开全文]

这个学习时长和流程,控制的太好了。特别是1分钟阅读的条件,简直完美。

 

第9、10章:分别是指针和结构体,重中之重中之重。

[展开全文]

11点02分

在不熟悉编程的情况下,对于新手而言,看到最重要的几条分别是:

 

1、【好好写注释】说明功能,以及实现方法,让别人更加清晰愉悦地读懂自己写的代码;

2、【名称写得直观易懂】不要过分简化也不要过分复杂,是让别人更加清晰愉悦地看自己的代码(例如马斯克在企业内不让大家使用缩写来表达,这个使得交流低效);

3、【团队合作】一起写代码,就像加入一支球队一样,适应这个球队的风格,就是,适应这个代码的编码风格;

4、【TODO注释】可以帮助自己快速地找到可以提升的待改进的代码部分。

[展开全文]

授课教师

C++算法工程师
高级算法研发工程师

课程特色

文档(9)
视频(50)
图文(22)
下载资料(3)