原文地址:C 语言入门,感谢作者前辈
25. 强制类型转换
强制类型转换是把变量从一种类型转换为另一种数据类型。例如,如果您想存储一个 long 类型的值到一个简单的整型中,您需要把 long 类型强制转换为 int 类型。您可以使用强制类型转换运算符来把值显式地从一种类型转换为另一种类型,如下所示:
(type_name) expression
复制代码
请看下面的实例,使用强制类型转换运算符把一个整数变量除以另一个整数变量,得到一个浮点数:
void main(){
void main(){
int sum = 20,count = 3;
double value,value2;
value = (double)sum / count;
value2 = sum / count;
printf("Value 强转 : %f Value2 wei强转 : %f\n ", value ,value2);
}
}
复制代码
输出:
Value 强转 : 6.666667 Value2 wei强转 : 6.000000
复制代码
整数提升
整数提升是指把小于 int 或 unsigned int 的整数类型转换为 int 或 unsigned int 的过程。请看下面的实例,在 int 中添加一个字符:
void main(){
//整数提升
int i= 17;
char c = 'c'; //在 ascii 中的值表示 99
int sum2;
sum2 = i + c;
printf("Value of sum : %d\n", sum2 );
}
复制代码
输出:
Value of sum : 116
复制代码
在这里,sum 的值为 116,因为编译器进行了整数提升,在执行实际加法运算时,把 'c' 的值转换为对应的 ascii 值。
26. 错误处理
C 语言不提供对错误处理的直接支持,但是作为一种系统编程语言,它以返回值的形式允许您访问底层数据。在发生错误时,大多数的 C 或 UNIX 函数调用返回 1 或 NULL,同时会设置一个错误代码 errno,该错误代码是全局变量,表示在函数调用期间发生了错误。您可以在 errno.h 头文件中找到各种各样的错误代码。
所以,C 程序员可以通过检查返回值,然后根据返回值决定采取哪种适当的动作。开发人员应该在程序初始化时,把 errno 设置为 0,这是一种良好的编程习惯。0 值表示程序中没有错误。
errno、perror() 和 strerror()
C 语言提供了 perror() 和 strerror() 函数来显示与 errno 相关的文本消息。
- perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。
- strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。
让我们来模拟一种错误情况,尝试打开一个不存在的文件。您可以使用多种方式来输出错误消息,在这里我们使用函数来演示用法。另外有一点需要注意,您应该使用 stderr 文件流来输出所有的错误。
例子:
void main(){
int dividend = 20;
int divsor = 0;
int quotient;
if (divsor == 0){
fprintf(stderr,"除数为 0 退出运行。。。\n");
exit(EXIT_FAILURE);
}
quotient = dividend / divsor;
fprintf(stderr,"quotient 变量的值为 : %d\n", quotient);
exit(EXIT_SUCCESS);
}
复制代码
输出:
除数为 0 退出运行。。。
复制代码
27. 递归
递归指的是在函数的定义中使用函数自身的方法。
语法格式如下:
void recursion()
{
statements;
... ... ...
recursion(); /* 函数调用自身 */
... ... ...
}
int main()
{
recursion();
}
复制代码
数的阶乘
double factorial(unsigned int i){
if (i <= 1){
return 1;
}
return i * factorial(i - 1);
}
void main(){
int i = 15;
printf("%d 的阶乘 %ld \n",i ,factorial(i));
}
复制代码
输出:
15 的阶乘 140732727129776
复制代码
斐波拉契数列
//斐波拉契数列
int fibonaci(int i){
if (i == 0){
return 0;
}
if (i == 1){
return 1;
}
return fibonaci(i - 1) + fibonaci( i -2);
}
void main(){
for (int j = 0; j < 10; j++) {
printf("%d\t\n", fibonaci(j));
}
}
复制代码
输出:
0
1
1
2
3
5
8
13
21
34
复制代码
28. 可变参数
有时,您可能会碰到这样的情况,您希望函数带有可变数量的参数,而不是预定义数量的参数。C 语言为这种情况提供了一个解决方案,它允许您定义一个函数,能根据具体的需求接受可变数量的参数。下面的实例演示了这种函数的定义。
int func(int, ... )
{
.
.
.
}
int main()
{
func(2, 2, 3);
func(3, 2, 3, 4);
}
复制代码
请注意,函数 func() 最后一个参数写成省略号,即三个点号(...),省略号之前的那个参数是 int,代表了要传递的可变参数的总数。为了使用这个功能,您需要使用 stdarg.h 头文件,该文件提供了实现可变参数功能的函数和宏。具体步骤如下:
- 定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数。
- 在函数定义中创建一个 va_list 类型变量,该类型是在 stdarg.h 头文件中定义的。
- 使用 int 参数和 va_start 宏来初始化 va_list 变量为一个参数列表。宏 va_start 是在 stdarg.h 头文件中定义的。
- 使用 va_arg 宏和 va_list 变量来访问参数列表中的每个项。
- 使用宏 va_end 来清理赋予 va_list 变量的内存。
现在让我们按照上面的步骤,来编写一个带有可变数量参数的函数,并返回它们的平均值:
例子:
double average(int num,...){
va_list vaList;
double sum = 0.0;
int i ;
//为 num 个参数初始化 valist
va_start(vaList,num);
//访问所有赋给 vaList 的参数
for (int j = 0; j < num; j++) {
sum += va_arg(vaList, int);
}
//清理为valist 保留的内存
va_end(vaList);
return sum/num;
}
void main(){
printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5));
printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15));
}
复制代码
输出:
Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000
复制代码
29. 内存管理
本章将讲解 C 中的动态内存管理。C 语言为内存的分配和管理提供了几个函数。这些函数可以在 <stdlib.h> 头文件中找到。
序号 | 函数和描述 |
---|---|
*void calloc(int num, int size); | 在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。所以它的结果是分配了 numsize 个字节长度的内存空间,并且每个字节的值都是0。 |
void free(void *address); | 该函数释放 address 所指向的内存块,释放的是动态分配的内存空间。 |
void *malloc(int num); | 在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。 |
void *realloc(void *address, int newsize); | 该函数重新分配内存,把内存扩展到 newsize。 |
**注意: ** void * 类型表示未确定类型的指针。C、C++ 规定 void * 类型可以通过类型转换强制转换为任何其它类型的指针。
动态分配内存
编程时,如果您预先知道数组的大小,那么定义数组时就比较容易。例如,一个存储人名的数组,它最多容纳 100 个字符,所以您可以定义数组,如下所示:
char name[100];
复制代码
但是,如果您预先不知道需要存储的文本长度,例如您向存储有关一个主题的详细描述。在这里,我们需要定义一个指针,该指针指向未定义所需内存大小的字符,后续再根据需求来分配内存,如下所示:
void main() {
char name[100];
char *description;
//将字符串 copy 到 name 中
strcpy(name, "迎娶白富美!");
//开始动态分配内存
description = (char *) malloc(200 * sizeof(char));
if (description == NULL) {
fprintf(stderr, "Error - unable to allocate required memory\n");
} else {
strcpy(description, "开始添加数据到 description 中");
}
printf("Name = %s\n", name );
printf("Description: %s sizeOf 大小 :%d\n", description , sizeof(description));
// 使用 free() 函数释放内存
free(description);
}
复制代码
输出:
Name = 迎娶白富美!
Description: 开始添加数据到 description 中 sizeOf 大小 :8
复制代码
30. 命令行参数
执行程序时,可以从命令行传值给 C 程序。这些值被称为命令行参数,它们对程序很重要,特别是当您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了。
命令行参数是使用 main() 函数参数来处理的,其中,argc 是指传入参数的个数,argv[] 是一个指针数组,指向传递给程序的每个参数。下面是一个简单的实例,检查命令行是否有提供参数,并根据参数执行相应的动作:
void main(int argc , char *argv[]){
if (argc ==1){
printf("argv[%d] == %d",0,*argv[0]);
}
else if (argc ==2){
printf("argv[%d] == %d",1,*argv[1]);
} else{
printf("匹配失败...");
}
}
复制代码
输出:
argv[0] == 47
复制代码
总结
不知道大家在看完 C 基础内容之后在对比下 Java 语法,是不是大部分都差不多,之前有的人说学了 C 在学其它语言都是小菜一碟,现在看来好像是这么回事。个人觉得其实只要会编程语言中的任何一门在学其它语言都会比较容易上手。
注:方便学习,侵删!
作者:DevYK
链接:https://juejin.im/post/5df8c917f265da339772a5d1
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。