怎样学好C语言编程

人气:343 ℃/2023-06-14 01:32:45

操作方法

首先一定要将c语言的基础知识学好,如果你连变量等基本的概念都不清楚,是不可能将这门语言学好的,打牢基础是学好的第一步。

建议安装turbo C等开发的软件,编程语言学习的最终目的就是用于程序的开发,C语言也不例外 ,要多进行实际操作,用c语言在开发环境下编译程序。

可以到C语言学习论坛去浏览相关的知识,在论坛上有很多狠经验丰富的前辈,多向他们学习,请教

遇到不懂得问题,多向老师请教,在老师上课的时候一定要认真听讲,特别是没有什么基础,从零开始学习言的同学,一定要认真上好每一节课。

怎样才能学好c语言

我要是在学习 C 语言之前知道这些就好了

【CSDN编者按】C语言是不少人的编程入门语言,本文作者惊呼,C语言太难了,要是我能早点知晓这些就好了!于是,他记录了学习C语言期间的一些好项目,CSDN 组织译者编译分享给大家。

原文链接:https://tmewett.com/c-tips/#good-projects-to-learn-from

作者:Tom M

译者:弯月

对于我来说,学习 C 语言好难啊。这门语言本身的基础知识并不是很难,但是“用 C 语言编程”需要用到各种知识,这些知识可没有那么容易掌握:

在本文中,我想总结一下 C 语言的学习要点和建议,希望能对你有所帮助。

学习资源

值得借鉴的项目

在学习的过程中,阅读一些 C 语言代码会很有帮助。

编译、链接、标题和符号

下面是一些关于如何编译 C 语言的基础知识。

C 语言的代码是用源文件 .c 编写的。每个源文件都会被编译成一个目标文件.o,这个文件就像一个容器装载了.c文件中编译后的函数。但这些函数是不可执行的。目标文件内部有一个符号表,这些符号是该文件中定义的全局函数和变量的名称。

# compile to objectscc -c thing.c -o thing.occ -c stuff.c -o stuff.o

源文件之间是完全独立的,可并行编译成对象。

如果想跨文件调用函数和变量,则必须使用头文件(.h)。这些文件也是 C 源文件,只不过使用方式比较特殊。回顾一下,目标文件只包含全局函数和变量的名称,没有类型、宏,甚至没有函数参数。如果想跨文件使用这些符号,就需要指定额外的信息。我们将这些“声明”单独放在 .h 文件中,然后由其他 .c 文件通过 #include 包含进来。

为避免重复,通常 .c 文件不会定义自己的类型/宏等,而是只包含自己或自己所属的模块或组件的头文件。

你可以将头文件视为 API 的规范,只不过实现可以放在多个源文件中。你甚至可以在同一个头文件中实现不同的平台或目的。

如果编译时遇到一个只有声明(例如通过头文件)、没有定义的符号引用时,编译出的目标文件会将其标记为缺失需要填补。

最终的这部分工作由编译器的“链接器”组件完成,由它负责将一个或多个对象连接在一起,匹配所有的符号引用,然后输出完整的可执行文件或共享库。

# link objects to executablecc thing.o stuff.o -o gizmo

概括起来,C语言的源文件中不能包含其他源文件,只能包括声明,然后由链接器完成匹配。

不推荐使用的功能

C 语言拥有悠长的发展历史,尽管 C 语言一直在努力实现向后兼容,但仍有一些功能是我们应该避免使用的。

数组不是值

在学习 C 语言的过程中,我们必须认识到,C 语言作为一种语言,只处理大小已知的数据块。你可以认为 C 语言是一种“复制已知大小值的语言”。

我们可以向程序传递整数或结构,通过函数返回它们,并将它们视为相应的对象,因为 C 知道它们的大小,因此 C 可以编译代码,并复制完整的数据。

然而,数组却完全不同。对于 C 语言来说,数组的大小是未知的。假设我在一个函数中声明了一个变量 int[5],实际上我得到的并不是类型 int[5] 的值,而是一个 int* 值,它指向的位置分配了 5 个整数。由于这只是一个指针,因此程序员必须代替语言来负责复制真正的数据并保证数据有效。

但是,结构内的数组与值一样,可以与结构一起复制。

(严格来讲,指定了大小的数组是真正的类型,而不仅仅是指针,例如你可以通过 sizeof 得知整个数组的大小。只不过,你不能将它们视为独立的值。)

编译器的各种选项

C 语言的编译器有很多选项,而且默认值不是很好用。下面是一些你可能需要的选项。

三种类型的内存,以及何时使用它们

自动存储:用于保存局部变量。当函数被调用时,就会创建一个新的自动存储区域,并在函数返回结果时删除。只有返回值会被保留,并被复制到调用它的函数的自动存储中。这意味着,返回一个指向局部变量的指针是不安全的,因为底层数据会被默默删除。自动存储通常被称为“栈”。

分配的存储:运行malloc 会返回的内存类型,这种内存会一直保留,直到被 free 函数释放,所以可以被传递到任何地方,包括返回给上级调用函数。通常被称为“堆”。

静态存储:在程序的整个生命周期内有效。在进程启动时分配,全局变量都存储在这里。

如果想通过一个函数“返回”内存,不必通过调用 malloc,可以直接将一个指向本地数据的指针传递给函数:

void getData(int *data) {data[0] = 1;data[1] = 4;data[2] = 9;}void main {int data[3];getData(data);printf("%d\n", data[1]);}

命名约定

C 语言不支持命名空间。如果你想编写一个公共库,或者想命名某个“模块”,则需要给所有公共 API 的名称加上一个前缀。这些名称包括:

另外,每个枚举也应该加上不同的前缀,这样才能分辨某个值属于哪种枚举类型:

enum color {COLOR_RED,COLOR_BLUE,...}

关于命名,并没有太多真正的约定,你可以随意选择蛇形命名法(snake_case)或驼峰式命名法(camelCase),但请记住保持一致!由于许多标准 C 类型都采用了 ptrdiff_t、int32_t 等形式,所以有人将类型命名为 my_type_t。

static

函数或文件级别的 static(静态)变量仅限文件内部访问。这些函数或变量不会作为符号导出,因此无法在其他源文件中使用。

static 也可以用在局部变量上,可以让变量在多次函数调用之间保持值不变。你可以将其视为一个仅限于该函数使用的全局变量。你可以利用 static 计算和存储数据,以供后续调用重用。但请记住,这种使用方法与全局状态或共享状态有同样的问题,例如线程安全、递归冲突等。

结构方法模式

如果你在学习 C 语言之前,学习过更有特色的语言,可能会发现很难将这些知识应用到 C 语言的学习中。例如,面向对象编程常见的一个概念:结构方法,即函数接受指向结构的指针,并通过指针修改结构或获取属性:

typedef struct {int x;int y;} vec2;void vec_add(vec2 *u, const vec2 *v) {u->x = v->x;u->y = v->y;}int vec_dot(const vec2 *u, const vec2 *v) {return u->x * v->x u->y * v->y;}

你无法扩展结构或实现类似于面向对象的功能,但采用这种思路来思考问题很有用。

const

以 const T 的形式声明类型 T 的变量或参数,则表示这个变量或参数不能被修改。这意味着,不能赋值,而且如果 T 是指针或数组类型,也不能被修改。

你可以将 T 转换为 const T,但反之不行。

设置函数的指针参数默认为 const 是一个好习惯,只有确实需要修改这些变量时再省略 const。

平台和标准 API

我们很难根据 #include <some_header.h> 来判断依赖项究竟是什么,它有可能来自:

你可以通过不依赖于平台的头文件与更多平台特定的代码进行交互,这样就可以通过不同的方式实现。许多流行的 C 库本质上只是对特定于平台的功能进行了统一的、精心设计的抽象。

整数

C 语言中的整数是一个非常大的坑。编写代码时,一定要小心。

大小

所有整数类型都有确定的最小位数。在一些常见的平台中,整数的大小都大于最小位数,例如 int 在 Windows、macOS 和 Linux 上都是 32 位的,但其最小位数是 16 位的。在编写可移植的代码时,你必须小心,不能让整数的大小超过最小位数。

如果想精确控制整数大小,可以使用 stdint.h 中的标准类型,如 int32_t、uint64_t 等。还有 _least_t 和 _fast_t 类型。

算术运算与整数提升

C语言中的算术运算有许多奇怪的规则,并产生意想不到的或不可移植的结果。

另外,请格外小心整数提升。

char 类型的符号

所有其他整数类型默认都有符号,但char可以有符号,也可以没有符号,具体取决于平台。因此,只有在作为字符时,这种类型才可移植。如果你想指定一个很小的数字,比如只有8位,也要指定符号。

宏与 const 变量

如果想定义一个非常简单的常量值,你有两种选择:

static const int my_constant = 5;// 或者#define MY_CONSTANT 5

二者的不同之处在于,前者是一个真正的变量,而后者是一个复制粘贴的行内表达式。

“常量表达式”实际上非常实用,因此常常被定义为宏。而变量则更适合更大或更复杂的值,如结构实例。

宏与内联函数

宏可以有参数,并扩展为 C 代码。

相较于函数,宏的优势在于:

缺点:

// 不推荐这种写法:#define MY_MACRO(x) x x// 应该写成:#define MY_MACRO(x) ((x) (x))

除非你需要多种泛型,否则可以直接定义静态内联函数(static inline function),这样就可以兼具二者的优点。内联表示,函数中的代码应该直接编译到使用的地方,而不是被调用。你可以将静态内联函数放在头文件中,就像宏一样。

推荐

首页/电脑版/网名
© 2026 NiBaKu.Com All Rights Reserved.