再学C语言,复习&笔记。


系列顺序:
Linux C语言编程基本原理与实践
Linux C语言指针与内存
Linux C语言结构体

更多Linux知识:
一天一点linux


预处理

编译的四个步骤:.c文件—>.i文件(预处理)->.s文件(编译)->.o文件(汇编)->可执行文件(链接)

gcc -o helloWorld.i helloWorld.c -E
-E表示只让helloWorld.c进行预处理

结构体

结构体对象所占的空间大小涉及到一个字节对齐的问题。字节对齐的目的是让计算机快速读写,是一个以空间换取时间的方式。
结构体对象的大小 = 最后一个成员的偏移量 + 最后一个成员变量的大小 + 填充字节
结构体字节对齐准则:当前成员的偏移量必须是成员变量大小的整数倍,不是的话在后面填充字节。
最后还要判断结构体大小是不是成员中最大成员类型的整数倍,不是的话还需填充。

例:

1
2
3
4
5
struct data{
int a;
char b;
int b;
};

a 4字节,b 1字节,c 4字节
计算方法:

  1. a的长度为4,为b的长度1的整数倍,故b的偏移量4字节。
  2. b的偏移量+b的长度=5字节,但5不能整除c的长度(4字节),故需填充偏移量到8字节。所以c的偏移量为8。
  3. c的偏移量+c的长度=8+4=12字节,且12字节是最大成员类型(4字节)的整数倍,故结构体所占空间为12字节。

注:C语言结构体和C++结构体定义的区别

  1. C结构体中只能自定义数据类型,不允许有函数。C++结构体可以加入成员函数,且允许该函数是虚函数。所以C结构体没有构造函数、析构函数和this指针。
  2. C结构体对内部成员变量的访问权限只能是public,C++结构体默认是public,可以是public,protected,private三种。
  3. C结构体不可继承,C++结构体可以从其它结构体或类继承。
    以上是表面区别,实际区别是面向过程和面向对象编程思路的区别:C的结构体只是把数据变量给包裹起来了,并不涉及算法。C++是把数据变量及对这些数据变量的相关算法给封装起来,并且给对这些数据和类不同的访问权限。
    C语言中没有类的概念,但可通过结构体内创建函数指针实现面向对象思想。
  4. 声明定义有区别:
    1
    2
    3
    4
    5
    struct weapon
    {
    int price;
    int atk;
    };

C语言用struct weapon a;
C++可以直接 weapon a;

若C也希望直接声明,则需引入typedef,定义为:

1
2
3
4
5
typedef struct weapon
{
int price;
int atk;
}Wea;

Wea a;

共用体

共用体的作用就使不同的类型的变量共享同一个地址,好处是节省开销,缺点是同一时刻仅仅能存储一个成员。
共用体的大小是所有成员中占内存最长的长度,初始化时只能有一个常量。

动态数据结构

静态链表

每一个结点都是在程序中定义的而不是临时开辟的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
struct weapon
{
int price;
int atk;
struct weapon \*next; //指向下一个节点
};

int main()
{
struct weapon a,b,c,\*head;
a.price = 100;
a.atk = 100;
b.price = 200;
b.atk = 200;
c.price = 300;
c.atk = 300;

head = &a;
a.next = &b;
b.next = &c;
c.next = NULL;

struct weapon \*p;
p = head;
while(p != NULL)
{
printf("%d, %d\n", p->atk, p->price);
p = p->next;
}
}

动态链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <malloc.h>
struct weapon
{
int price;
int atk;
struct weapon \*next;
};

struct weapon * create()
{
struct weapon * head;
struct weapon * p1, *p2;//p1当前结点,p2上一个结点
int n = 0;//记录链表长度
p1 = p2 = (struct weapon*)malloc(sizeof(struct weapon));
scanf("%d,%d",&p1->price,&p1->atk);
head = NULL;
while(p1->price!=0)//约定价格为0时停止输入
{
n++;
if(n == 1)
{
head = p1;
}
else
{
p2->next = p1;
}
p2 = p1;
p1 = (struct weapon*)malloc(sizeof(struct weapon));
scanf("%d,%d",&p1->price, &p1->atk);
}
}

int main()
{
struct weapon *p;
p = create();
printf("%d,%d",p->price,p->atk);
return 0;
}

注:更多数据结构知识请参阅《数据结构(C语言版)》。

递归与递推

递归:将一个问题规模为n的问题降为规模为(n-1)的问题,然后依次降低规模(层层往下),直至问题得到低规模的解,之后依次带入高规模的问题中(层层往上),最终得到规模为n解。从n -> 1 -> n。
递推:先构造解决一个低的规模问题,然后依次(层层往上)推导出高规模的问题解。
从1 -> n。