C09-others

本文最后更新于:26 分钟前

C错误处理

在发生错误时,大多数的 C 或 UNIX 函数调用返回 1 或 NULL,同时会设置一个错误代码 errno,该错误代码是全局变量,表示在函数调用期间发生了错误。在 errno.h 头文件中可以找到各种各样的错误代码。
在程序初始化时,把 errno 设置为 0,0 值表示程序中没有错误,这是一种良好的编程习惯。

errno、perror() 和 strerror()
C 语言提供了 perror() 和 strerror() 函数来显示与 errno 相关的文本消息。

  • perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。
  • strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。

程序退出状态

通常情况下,程序成功执行完一个操作正常退出的时候会带有值 EXIT_SUCCESS。在这里,EXIT_SUCCESS 是宏,它被定义为 0。

如果程序中存在一种错误情况,当退出程序时,会带有状态值 EXIT_FAILURE,被定义为 -1。

C其他

http://c.biancheng.net/c/example/

内存管理

C 语言为内存的分配和管理提供了几个函数。这些函数可以在 <stdlib.h> 头文件中找到。

序号 函数和描述
1 void *calloc(int num, int size); 在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。所以它的结果是分配了 num*size 个字节长度的内存空间,并且每个字节的值都是0。

|2|void free(void *address);|该函数释放 address 所指向的内存块,释放的是动态分配的内存空间。
|3|void *malloc(int num);|在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。|
|4|void *realloc(void *address, int newsize);|该函数重新分配内存,把内存扩展到 newsize。|
注意:void * 类型表示未确定类型的指针。C、C++ 规定 void * 类型可以通过类型转换强制转换为任何其它类型的指针。

命令行参数

执行程序时,可以从命令行传值给 C 程序。这些值被称为命令行参数,它们对程序很重要,特别是当您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了。

命令行参数是使用 main() 函数参数来处理的,其中,argc 是指传入参数的个数,argv[] 是一个指针数组,指向传递给程序的每个参数。下面是一个简单的实例,检查命令行是否有提供参数,并根据参数执行相应的动作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

int main( int argc, char *argv[] )
{
if( argc == 2 )
{
printf("The argument supplied is %s\n", argv[1]);
}
else if( argc > 2 )
{
printf("Too many arguments supplied.\n");
}
else
{
printf("One argument expected.\n");
}
}

使用一个参数,编译并执行上面的代码,它会产生下列结果:

1
2
$./a.out testing
The argument supplied is testing

使用两个参数,编译并执行上面的代码,它会产生下列结果:

1
2
$./a.out testing1 testing2
Too many arguments supplied.

不传任何参数,编译并执行上面的代码,它会产生下列结果:

1
2
$./a.out
One argument expected

应当指出的是,argv[0] 存储程序的名称,argv[1] 是一个指向第一个命令行参数的指针,*argv[n] 是最后一个参数。如果没有提供任何参数,argc 将为 1,否则,如果传递了一个参数,argc 将被设置为 2。

递归

数的阶乘

下面的实例使用递归函数计算一个给定的数的阶乘:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

double factorial(unsigned int i)
{
if(i <= 1)
{
return 1;
}
return i * factorial(i - 1);
}
int main()
{
int i = 15;
printf("%d 的阶乘为 %f\n", i, factorial(i));
return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

15 的阶乘为 1307674368000.000000

斐波那契数列

下面的实例使用递归函数生成一个给定的数的斐波那契数列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>

int fibonaci(int i)
{
if(i == 0)
{
return 0;
}
if(i == 1)
{
return 1;
}
return fibonaci(i-1) + fibonaci(i-2);
}

int main()
{
int i;
for (i = 0; i < 10; i++)
{
printf("%d\t\n", fibonaci(i));
}
return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

0
1
1
2
3
5
8
13
21
34

指针处理链表

https://www.runoob.com/w3cnote/c-structures-intro.html

链表概述

链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。

链表有一个 头指针 变量,它存放一个地址,该地址指向一个元素,链表中每一个元素称为 结点,每个结点都应包括两个部分,一为用户需要用的实际数据,二为下一个结点的地址。可以看出,头指针 head 指向第一个元素,第一个元素又指向第二个元素,。。。。直到最后一个元素,该元素不再指向其他元素,它称为 表尾,它的地址部分放一个 NULL(表示 空地址)链表到此结束。

可以看到链表中各元素在内存中可以不是连续存放的,要找某一元素,必须先找到上一个元素,根据它提供的下一元素地址才能找到下一个元素。如果不提供 头指针 head 则整个链表无法访问。

可以看到。这种链表的数据结构,必须利用指针变量才能实现,即一个结点中应包含一个指针变量,用它存放下一结点的地址。

前面介绍了结构体变量,用它作链表中的结点是最合适的,一个结构体变量包含若干成员,这些成员可以是数值类型,字符类型,数组类型,也可以是指针类型,我们用这个指针类型成员来存放下一个结点的地址。例如可以设计这样一个结构体类型:

1
2
3
4
5
6
struct student
{
int num;
float score;
struct student *next;
};

其中成员 num 和 score 用来存放结点中的有用数据(用户需要用到的数据),next 是指针类型成员,它指向 struct student 类型数据(这是 next 所在结构体类型)。一个指针类型的成员既可以指向其他类型的结构体数据,也可以指向自己所在的结构体类型的数据。现在 next 是 struct student 类型中的一个成员,它又指向 struct student 类型的数据。用这种方法就可以建立链表。

请注意:只是定义一个 struct student 类型,并未实际分配存储空间,只有定义了变量才分配内存单元。

简单链表

下面通过一个例子来说明如何建立和输出一个简单链表:

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
#include <stdio.h>
#include <stdlib.h>

#define NULL 0

struct student
{
long num;
float score;
struct student *next;
};

void main()
{
struct student a, b, c, *head, *p;
a.num = 99101; a.score = 89.5;
b.num = 99103; b.score = 90;
c.num = 99107; c.score = 85;//对结点的 num 和 score 成员赋值
head = &a;//将结点 a 的起始地址赋给头指针 head
a.next = &b;//将结点 b 的起始地址赋给 a 结点的 next 成员
b.next = &c;
c.next = NULL;// c 结点的 next 成员不存放其他结点地址
p = head;//使 p 指针指向 a 结点
do
{
printf("%ld %5.1f\n", p->num, p->score);// 输出 p 指向的结点的数据
p = p->next;//使 p 指向下一结点
}while(p != NULL);//输出完 c 结点后 p 的值为 NULL
system("pause");
}

运行结果:

99101 89.5
99103 90.0
99107 85.0

处理动态链表所需的函数

(1)malloc 函数

void *malloc(unsigned int size);

作用是在内存的动态存储区中分配一个长度为 size 的连接空间。些函数的值(即返回值)是一个指向分配空间起始地址的指针(基类型为 void)。如果些函数未能成功地执行(例如内存空间不足)则返回空指针 NULL。

(2)calloc 函数

void *calloc(unsigned n, unsigned size);

其作用是在内存的动态区存储中分配 n 个长度为 size 的连续空间。函数返回一个指向分配空间起始地址的指针,如果分配不成功,返回 NULL。 用 calloc 函数可以为一维数组开辟动态存储空间, n 为数组元素个数,每个元素长度为 size。

(3)free 函数

void free(void *p);

其作用是释放由 p 指向的内存区,使这部分内存区能被其它变量使用, p 是最后一次调用 calloc 或 malloc 函数时返回的值。free 函数无返回值。 请注意:以前的C版本提供的 malloc 和 calloc 函数得到的是指向字符型数据的指针。ANSI C 提供的 malloc 和 calloc 函数规定为 void * 类型。

建立动态链表

所谓建立动态链表是指在程序执行过程中从无到有地建立起一个键表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <stdio.h>
#include <stdlib.h>

#define NULL 0
#define LEN sizeof(struct student)

struct student
{
long num;
float score;
struct student *next;
};

struct student *create()
{
struct student *p1, *p2, *head;
int num;
float score;
int n = 0;

head = NULL;

p1 = p2 = (struct student *)malloc(LEN);

printf("please input num and score.\n");
scanf("%d,%f", &p1->num, &p1->score);

while(p1->num != 0)
{
n ++;
if(n == 1)
head = p1;
else
p2->next = p1;
p2 = p1;
p1 = (struct student *)malloc(sizeof(struct student));

printf("please input num and score.\n");

scanf("%d,%f", &p1->num, &p1->score);
}
p2->next = NULL;
return head;
}

void printlist(struct student *head)
{
struct student *p;
p = head;
if(head != NULL)
{
do
{
printf("num=%d score=%f\n", p->num, p->score);
p = p->next;
}while(p != NULL);
}
}

void main()
{
struct student *head;
head = create();
printlist(head);
system("pause");
}

链表的各种操作

打印链表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void printlist(struct student *head)
{
struct student *p;
p = head;

if(head != NULL)
{
do
{
printf("num=%d score=%5.2f\n", p->num, p->score);
p = p->next;
} while (p != NULL);
}
/* while(p -> next != NULL)
{
printf("num=%d score=%f\n", p->num, p->score);
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
struct student *delNode(struct student *head, int num)
{
printf("delNode.\n");
struct student *p1, *p2;
if(head == NULL)
{
printf("The List is NULL.\n");
}
else
{
p1 = head;
while(p1->next != NULL && p1->num != num)
{
p2 = p1;
p1 = p1->next;
}
if(p1->num == num)
{
if(p1 == head)
head = p1->next;
else
p2->next = p1->next;
}
else
printf("Can not find list num.\n");
}
return head;
}

更新节点:

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
struct student *update(struct student *head, int index, int num, float score)
{
printf("update.\n");
struct student *p;
if(head == NULL)
{
printf("The List is NULL.\n");
}
else
{
p = head;
while(p->next != NULL && p->num != index)
{
p = p->next;
}
if(p->num == index)
{
p->num = num;
p->score = score;
}
else
printf("Can not find list index.\n");
}
return head;
}

增加节点:

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
struct student *add(struct student *head, int index, int num, float score)
{
printf("add.\n");
struct student *p1, *p2, *p3;
if(head == NULL)
{
printf("The List is NULL.\n");
}
else
{
p1 = p2 = head;
while(p1->next != NULL && p1->num != index)
{
p1 = p1->next;
p2 = p1;
}
if(p1->num == index)
{
p3 = (struct student *)malloc(LEN);
p3->num = num;
p3->score = score;

if(p2->next == NULL)
{
p2->next = p3;
p3->next = NULL;
}
else
{
p3->next = p2->next;
p2->next = p3;
}
}
else
printf("Can not find list index.\n");
}
return head;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!