Linux C 一站式学习 第一部分基础知识

来源:互联网 发布:淘宝企业店铺要钱吗 编辑:程序博客网 时间:2024/05/19 19:13

1. 声明和定义

C 语言中的声明(Declaration)有变量声明,函数声明和类型声明三种。

如果一个变量或函数的声明要求编译器为它分配存储空间,那么也可以成为定义(Definition),因此定义是声明的一种。分配存储空间的函数声明可以称为函数定义。


2. 变量命名

标识符:C语言中变量,函数名,宏定义,结构体成员名等都通称为标识符(Identifier)。

一般来讲应避免使用以下划线开头的标识符,以下划线开头的标识符只要不和C语言关键字冲突都是合法的,但是往往被编译器用作一些功能扩展(如第18.4节讲的gcc的_attribute_语法),C标准库也定义了很多以下划线开头的标识符留作内部使用,所以除非对编译器的特征和C标准库的实现特别清楚,一般应避免使用这种标识符,以免造成命名冲突。


3. 函数声明与函数定义

只有带函数体的声明才叫做定义。



4. 记住“先声明后使用”的原则。(注意顺序)


5. 形参和实参

形参想到与函数中定义的变量,调用函数传递参数的过程相当于定义形参变量并且用实参的值来初始化。


6. man 命令介绍



7. 局部变量可以用类型相符的任意表达式来初始化,而全局变量只能用常量表达式来初始化。


局部变量在使用前一定要先赋值,不然会系统会赋一个不确定的值。

8. 在一个函数体中可以声明另一个函数,但不能定义另一个函数,C 语言不允许嵌套定义函数(注:gcc的扩展特性允许嵌套定义函数)。

9. 学习编程语言:



10. 结构体

(1). 定义

(1.1).

  1. // complex_struct为标识符(名字),这种标识符在C语言中被称为Tag
  2. struct complex_struct {
  3.    double x, y;
  4. };
  5. // 注:结尾必须加分号
(1,2). 定义变量
A. 带Tag(标识符)的结构体,可以定义变量
  1. // 后面的 z1,z2为定义的变量
  2. struct complex_struct {
  3.    double x, y;
  4. } z1, z2;
  5. // 对于带Tag的结构体,可以像基本类型那样定义变量
  6. struct complex_struct z3, z4;
B. 不带的结构体
  1. // 不带Tag,这样的结构体不能再定义额外的变量
  2. struct {
  3.    double x, y;
  4. } z1, z2;

11. 枚举常量使用一种整型,其值是在编译时确定。

12. 数组

(1). 数组不能相互赋值或者相互初始化。错误的例子

  1. // 下面的例子是错的
  2. int a[5] = {4, 3, 2, 1};
  3. int b[5] = a; // 这样是错的
  4. a = b; // 这样相互赋值也是错误的
(2). 数组不能相互赋值,也就不能用数组类型作为函数的参数或者返回值。错误的例子:
  1. // 下面是错误的例子
  2. // 定义参数为数组的函数,这样是错误的
  3. void foo(int a[5])
  4. {
  5.    ...
  6. }
  7. // 调用
  8. int array[5] = {0};
  9. foo(array);
(3). 对数组类型有一条特殊规则,导致的这个问题。
数组类型做右值使用时,自动转换成指向数组首元素的指针。所有上面的函数调用其实是传递一个指针类型的参数,而不是数组类型的参数。


13. 编译器的工作分为两个阶段,先是预处理(Preprocess)阶段,然后才是编译阶段。用gcc的-E选项可以看到预处理之后、编译之前的程序。

像 #include 和 #define 这种以 # 号开头的行称为预处理指示(Preprocess Directive)。使用 cpp ***.c 也可查看预处理的结果,它只做预处理而不做编译,cpp 表示 C preprocessor。


14. #define

首先,define 不仅用于定义常量,而且可以定义更复杂的语法结构,称为宏(Macro)定义。其次,define 定义是在预处理阶段处理的,而枚举是在编译阶段处理的。


15. 字符串

每个字符串末尾都有一个字符"\0"做结束符,这里的\0是ASCII码的八进制表示,也就是ASCII码为0的Null字符,所以字符串也称为“以Null结尾的字符串”。


16. 多维数组

注意:除了第一维的数组长度可以有编译器自动计算而不需要指定,其他各维的都必须明确指定长度。

eg:

  1. int a[][2] = {{1,2}, {3, 4}, {5,}};

17. gdb:使用gdb工具调试程序


断电相关:


观察点:


如果某个函数的局部变量发生访问越界,有可能并不立即产生段错误,而是在函数返回时产生段错误。


18. 时间复杂度



19. 排序

(1). 插入排序:时间复杂度为O(n^2);

(2). 归并排序:时间复杂度为O(nlgn);

        步骤:        

        a: Divide: 把长度为n的输入序列分成两个长度为n/2的子序列;

        b: Conquer: 对这两个子序列分别采用归并排序。

        c: Combine: 将两个排序好的子序列合并成一个最终的排序序列。

(3). 快速排序


20. 查找

(1). 线性查找

(2). 折半查找:从一组排好序的序列中找出某个元素的位置,可以使用折半查找。


21. 断言(Assertion):有效地测试程序

相关头文件:assert.h


只Debug时调用测试代码,Release时不调用:

(方式一). #define NDEBUG:测试代码只在开发和调试时有用。如果在包含assert.h之前定义一个NDEBUG宏(表示No Debug),就可以禁用 assert.h 中的 assert 宏定义,这样代码中的所以 assert 测试都江不起作用。

Eg:

  1. #define NDEBUG // 必须在头文件assert.h之前定义
  2. #include <stdio.h>
  3. #include <assert.h>
(方式二). 在编译命令行中加入 -NDEBUG 选项就行。这样不必修改源文件,而且这样相当于在源文件开头定义了 NDEBUG 宏。

0 0
原创粉丝点击