导图社区 C语言【二】
C语言是一种通用、高效的编程语言,由丹尼斯·里奇于1972年开发。它结合了高级语言的易读性和低级语言的硬件操作能力,广泛应用于系统编程。C语言提供了强大的移植性,可以在多种计算机平台上运行。其简洁紧凑的语法结构、丰富的运算符和多样的数据类型使得C语言在编写系统软件如UNIX操作系统时显得尤为适用。C语言的高效性和灵活性使其成为开发者的首选工具之一。
编辑于2024-07-20 23:17:00这是一篇关于第六章 学习法治思想 提升法治素养的思维导图,主要内容包括:第四节 自觉尊法学法守法用法,第三节 维护宪法权威,第二节 坚持全面依法治国,第一节 社会主义法治的特征和运行。
大一新生的注意事项简洁而关键。首先,合理规划课程和时间,确保充足的学习与复习时间。其次,熟悉学校资源如图书馆、学习中心,充分利用这些设施。参与课外活动和社团,培养兴趣并扩展社交圈。建立良好的生活习惯,包括健康饮食和适量运动。最后,保持开放心态,积极适应大学生活,勇于尝试新事物。简而言之,大一是需要你探索自我、发展个人能力,并为未来职业生涯打下基础的关键时期。
C语言是一种通用、高效的编程语言,由丹尼斯·里奇于1972年开发。它结合了高级语言的易读性和低级语言的硬件操作能力,广泛应用于系统编程。C语言提供了强大的移植性,可以在多种计算机平台上运行。其简洁紧凑的语法结构、丰富的运算符和多样的数据类型使得C语言在编写系统软件如UNIX操作系统时显得尤为适用。C语言的高效性和灵活性使其成为开发者的首选工具之一。
社区模板帮助中心,点此进入>>
这是一篇关于第六章 学习法治思想 提升法治素养的思维导图,主要内容包括:第四节 自觉尊法学法守法用法,第三节 维护宪法权威,第二节 坚持全面依法治国,第一节 社会主义法治的特征和运行。
大一新生的注意事项简洁而关键。首先,合理规划课程和时间,确保充足的学习与复习时间。其次,熟悉学校资源如图书馆、学习中心,充分利用这些设施。参与课外活动和社团,培养兴趣并扩展社交圈。建立良好的生活习惯,包括健康饮食和适量运动。最后,保持开放心态,积极适应大学生活,勇于尝试新事物。简而言之,大一是需要你探索自我、发展个人能力,并为未来职业生涯打下基础的关键时期。
C语言是一种通用、高效的编程语言,由丹尼斯·里奇于1972年开发。它结合了高级语言的易读性和低级语言的硬件操作能力,广泛应用于系统编程。C语言提供了强大的移植性,可以在多种计算机平台上运行。其简洁紧凑的语法结构、丰富的运算符和多样的数据类型使得C语言在编写系统软件如UNIX操作系统时显得尤为适用。C语言的高效性和灵活性使其成为开发者的首选工具之一。
C语言【二】
C 指针
定义:type *var-name;
如何使用指针? 使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。下面的实例涉及到了这些操作: 实例 #include <stdio.h> int main () { int var = 20; /* 实际变量的声明 */ int *ip; /* 指针变量的声明 */ ip = &var; /* 在指针变量中存储 var 的地址 */ printf("Address of var variable: %p\n", &var ); /* 在指针变量中存储的地址 */ printf("Address stored in ip variable: %p\n", ip ); /* 使用指针访问值 */ printf("Value of *ip variable: %d\n", *ip ); return 0; }
C 函数指针与回调函数
函数指针 函数指针是指向函数的指针变量。 通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。 函数指针可以像一般函数一样,用于调用函数、传递参数。 函数指针变量的声明: typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
回调函数 函数指针作为某个函数的参数
C 字符串
C 字符串 在 C 语言中,字符串实际上是使用 null 字符 '\0' 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。 下面的声明和初始化创建了一个 "Hello" 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 "Hello" 的字符数多一个。 char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; 依据数组初始化规则,您可以把上面的语句写成以下语句: char greeting[] = "Hello";
序号 函数 & 目的 1 strcpy(s1, s2); 复制字符串 s2 到字符串 s1。 2 strcat(s1, s2); 连接字符串 s2 到字符串 s1 的末尾。 3 strlen(s1); 返回字符串 s1 的长度。 4 strcmp(s1, s2); 如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回小于 0;如果 s1>s2 则返回大于 0。 5 strchr(s1, ch); 返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。 6 strstr(s1, s2); 返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
#include <string.h>
C 结构体
定义结构 为了定义结构,您必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下: struct tag { member-list member-list member-list ... } variable-list ;
struct Books { char title[50]; char author[50]; char subject[100]; int book_id; } book;
结构体变量的初始化 和其它类型变量一样,对结构体变量可以在定义时指定初始值。
struct Books { char title[50]; char author[50]; char subject[100]; int book_id; } book = {"C 语言", "RUNOOB", "编程语言", 123456};
访问结构成员 为了访问结构的成员,我们使用成员访问运算符(.)
printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book.title, book.author, book.subject, book.book_id);
结构作为函数参数 您可以把结构作为函数参数,传参方式与其他类型的变量或指针类似。
/* 函数声明 */ void printBook( struct Books book );
指向结构的指针 您可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似
void printBook( struct Books *book ) { printf( "Book title : %s\n", book->title); printf( "Book author : %s\n", book->author); printf( "Book subject : %s\n", book->subject); printf( "Book book_id : %d\n", book->book_id); } /* 通过传 Book1 的地址来输出 Book1 信息 */ printBook( &Book1 );
C 共用体
共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。 定义共用体 为了定义共用体,您必须使用 union 语句,方式与定义结构类似。union 语句定义了一个新的数据类型,带有多个成员。union 语句的格式如下: union [union tag] { member definition; member definition; ... member definition; } [one or more union variables];
union Data { int i; float f; char str[20]; } data;
访问共用体成员 为了访问共用体的成员,我们使用成员访问运算符(.)
C 位域
位域声明 在结构内声明位域的形式如下: struct { type [member_name] : width ; };
struct { unsigned int age : 3; } Age;
C typedef
C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字
typedef unsigned char BYTE;BYTE b1, b2;
typedef vs #define #define 是 C 指令,用于为各种数据类型定义别名,与 typedef 类似,但是它们有以下几点不同: typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。 typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。
C 输入 & 输出
标准文件 C 语言把所有的设备都当作文件。所以设备(比如显示器)被处理的方式与文件相同。以下三个文件会在程序执行时自动打开,以便访问键盘和屏幕。 标准文件 文件指针 设备 标准输入 stdin 键盘 标准输出 stdout 屏幕 标准错误 stderr 您的屏幕 文件指针是访问文件的方式,本节将讲解如何从屏幕读取值以及如何把结果输出到屏幕上。 C 语言中的 I/O (输入/输出) 通常使用 printf() 和 scanf() 两个函数。 scanf() 函数用于从标准输入(键盘)读取并格式化, printf() 函数发送格式化输出到标准输出(屏幕)。
getchar() & putchar() 函数 int getchar(void) 函数从屏幕读取下一个可用的字符,并把它返回为一个整数。这个函数在同一个时间内只会读取一个单一的字符。您可以在循环内使用这个方法,以便从屏幕上读取多个字符。 int putchar(int c) 函数把字符输出到屏幕上,并返回相同的字符。这个函数在同一个时间内只会输出一个单一的字符。您可以在循环内使用这个方法,以便在屏幕上输出多个字符。
#include <stdio.h> int main( ) { int c; printf( "Enter a value :"); c = getchar( ); printf( "\nYou entered: "); putchar( c ); printf( "\n"); return 0; }
gets() & puts() 函数 char *gets(char *s) 函数从 stdin 读取一行到 s 所指向的缓冲区,直到一个终止符或 EOF。 int puts(const char *s) 函数把字符串 s 和一个尾随的换行符写入到 stdout。
#include <stdio.h> int main( ) { char str[100]; printf( "Enter a value :"); gets( str ); printf( "\nYou entered: "); puts( str ); return 0; }
scanf() 和 printf() 函数 int scanf(const char *format, ...) 函数从标准输入流 stdin 读取输入,并根据提供的 format 来浏览输入。 int printf(const char *format, ...) 函数把输出写入到标准输出流 stdout ,并根据提供的格式产生输出。 format 可以是一个简单的常量字符串,但是您可以分别指定 %s、%d、%c、%f 等来输出或读取字符串、整数、字符或浮点数。还有许多其他可用的格式选项,可以根据需要使用。如需了解完整的细节,可以查看这些函数的参考手册
C 文件读写
打开文件 您可以使用 fopen( ) 函数来创建一个新的文件或者打开一个已有的文件,这个调用会初始化类型 FILE 的一个对象,类型 FILE 包含了所有用来控制流的必要的信息。下面是这个函数调用的原型: FILE *fopen( const char * filename, const char * mode ); 在这里,filename 是字符串,用来命名文件,访问模式 mode 的值可以是下列值中的一个: 模式 描述 r 打开一个已有的文本文件,允许读取文件。 w 打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。 a 打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。 r+ 打开一个文本文件,允许读写文件。 w+ 打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。 a+ 打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。 如果处理的是二进制文件,则需使用下面的访问模式来取代上面的访问模式: "rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"
关闭文件 为了关闭文件,请使用 fclose( ) 函数。函数的原型如下: int fclose( FILE *fp ); 如果成功关闭文件,fclose( ) 函数返回零,如果关闭文件时发生错误,函数返回 EOF。这个函数实际上,会清空缓冲区中的数据,关闭文件,并释放用于该文件的所有内存。EOF 是一个定义在头文件 stdio.h 中的常量。 C 标准库提供了各种函数来按字符或者以固定长度字符串的形式读写文件。
读取文件 下面是从文件读取单个字符的最简单的函数: int fgetc( FILE * fp ); fgetc() 函数从 fp 所指向的输入文件中读取一个字符。返回值是读取的字符,如果发生错误则返回 EOF。下面的函数允许您从流中读取一个字符串: char *fgets( char *buf, int n, FILE *fp ); 函数 fgets() 从 fp 所指向的输入流中读取 n - 1 个字符。它会把读取的字符串复制到缓冲区 buf,并在最后追加一个 null 字符来终止字符串。 如果这个函数在读取最后一个字符之前就遇到一个换行符 '\n' 或文件的末尾 EOF,则只会返回读取到的字符,包括换行符。您也可以使用 int fscanf(FILE *fp, const char *format, ...) 函数来从文件中读取字符串,但是在遇到第一个空格和换行符时,它会停止读取。
#include <stdio.h> int main() { FILE *fp = NULL; char buff[255]; fp = fopen("/tmp/test.txt", "r"); fscanf(fp, "%s", buff); printf("1: %s\n", buff ); fgets(buff, 255, (FILE*)fp); printf("2: %s\n", buff ); fgets(buff, 255, (FILE*)fp); printf("3: %s\n", buff ); fclose(fp); }
二进制 I/O 函数 下面两个函数用于二进制输入和输出: size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file); size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file); 这两个函数都是用于存储块的读写 - 通常是数组或结构体。
C 预处理器
C 预处理器 C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器(C Preprocessor)简写为 CPP。 所有的预处理器命令都是以井号(#)开头。它必须是第一个非空字符,为了增强可读性,预处理器指令应从第一列开始。下面列出了所有重要的预处理器指令: 指令 描述 #define 定义宏 #include 包含一个源代码文件 #undef 取消已定义的宏 #ifdef 如果宏已经定义,则返回真 #ifndef 如果宏没有定义,则返回真 #if 如果给定条件为真,则编译下面代码 #else #if 的替代方案 #elif 如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码 #endif 结束一个 #if……#else 条件编译块 #error 当遇到标准错误时,输出错误消息 #pragma 使用标准化方法,向编译器发布特殊的命令到编译器中
#define MAX_ARRAY_LENGTH 20 这个指令告诉 CPP 把所有的 MAX_ARRAY_LENGTH 替换为 20。使用 #define 定义常量来增强可读性。 #include <stdio.h> #include "myheader.h" 这些指令告诉 CPP 从系统库中获取 stdio.h,并添加文本到当前的源文件中。下一行告诉 CPP 从本地目录中获取 myheader.h,并添加内容到当前的源文件中。 #undef FILE_SIZE #define FILE_SIZE 42 这个指令告诉 CPP 取消已定义的 FILE_SIZE,并定义它为 42。 #ifndef MESSAGE #define MESSAGE "You wish!" #endif
C 头文件
C 头文件 头文件是扩展名为 .h 的文件,包含了 C 函数声明和宏定义,被多个源文件中引用共享。有两种类型的头文件:程序员编写的头文件和编译器自带的头文件。
引用头文件的语法 使用预处理指令 #include 可以引用用户和系统头文件。它的形式有以下两种: #include <file> 这种形式用于引用系统头文件。它在系统目录的标准列表中搜索名为 file 的文件。在编译源代码时,您可以通过 -I 选项把目录前置在该列表前。 #include "file" 这种形式用于引用用户头文件。它在包含当前文件的目录中搜索名为 file 的文件。在编译源代码时,您可以通过 -I 选项把目录前置在该列表前。
只引用一次头文件
有条件引用
C 强制类型转换
C 强制类型转换 强制类型转换是把变量从一种类型转换为另一种数据类型。
(type_name) expression
C 错误处理
C 错误处理 C 语言不提供对错误处理的直接支持,但是作为一种系统编程语言,它以返回值的形式允许您访问底层数据。在发生错误时,大多数的 C 或 UNIX 函数调用返回 1 或 NULL,同时会设置一个错误代码 errno,该错误代码是全局变量,表示在函数调用期间发生了错误。您可以在 errno.h 头文件中找到各种各样的错误代码。 所以,C 程序员可以通过检查返回值,然后根据返回值决定采取哪种适当的动作。开发人员应该在程序初始化时,把 errno 设置为 0,这是一种良好的编程习惯。0 值表示程序中没有错误。
errno、perror() 和 strerror() C 语言提供了 perror() 和 strerror() 函数来显示与 errno 相关的文本消息。 perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。 strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。
被零除的错误 在进行除法运算时,如果不检查除数是否为零,则会导致一个运行时错误。 为了避免这种情况发生,下面的代码在进行除法运算前会先检查除数是否为零:
C 递归
递归指的是在函数的定义中使用函数自身的方法。
数的阶乘
斐波那契数列
0、1、1、2、3、5、8、13、21、34、……
F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)
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 变量的内存。
#include <stdio.h> #include <stdarg.h> double average(int num,...) { va_list valist; double sum = 0.0; int i; /* 为 num 个参数初始化 valist */ va_start(valist, num); /* 访问所有赋给 valist 的参数 */ for (i = 0; i < num; i++) { sum += va_arg(valist, int); } /* 清理为 valist 保留的内存 */ va_end(valist); return sum/num; } int 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
C 内存管理
本章将讲解 C 中的动态内存管理。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。
动态分配内存 编程时,如果您预先知道数组的大小,那么定义数组时就比较容易
char *description; /* 动态分配内存 */ description = (char *)malloc( 200 * sizeof(char) ); if( description == NULL ) { fprintf(stderr, "Error - unable to allocate required memory\n"); } else { strcpy( description, "Zara ali a DPS student in class 10th"); } 上面的程序也可以使用 calloc() 来编写,只需要把 malloc 替换为 calloc 即可,如下所示: calloc(200, sizeof(char));
C 命令行参数
执行程序时,可以从命令行传值给 C 程序。这些值被称为命令行参数,它们对程序很重要,特别是当您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了。 命令行参数是使用 main() 函数参数来处理的,其中,argc 是指传入参数的个数,argv[] 是一个指针数组,指向传递给程序的每个参数。下面是一个简单的实例,检查命令行是否有提供参数,并根据参数执行相应的动作:
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"); } } $./a.out testing The argument supplied is testing 使用两个参数,编译并执行上面的代码,它会产生下列结果: $./a.out testing1 testing2 Too many arguments supplied.
C 排序算法
冒泡排序 冒泡排序(英语:Bubble Sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。
#include <stdio.h> void bubble_sort(int arr[], int len) { int i, j, temp; for (i = 0; i < len - 1; i++) for (j = 0; j < len - 1 - i; j++) if (arr[j] > arr[j + 1]) { temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } int main() { int arr[] = { 22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70 }; int len = (int) sizeof(arr) / sizeof(*arr); bubble_sort(arr, len); int i; for (i = 0; i < len; i++) printf("%d ", arr[i]); return 0; }
选择排序 选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
void swap(int *a,int *b) //交換兩個變數 { int temp = *a; *a = *b; *b = temp; } void selection_sort(int arr[], int len) { int i,j; for (i = 0 ; i < len - 1 ; i++) { int min = i; for (j = i + 1; j < len; j++) //走訪未排序的元素 if (arr[j] < arr[min]) //找到目前最小值 min = j; //紀錄最小值 swap(&arr[min], &arr[i]); //做交換 } }
插入排序 插入排序(英语:Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到 {\displaystyle O(1)} {\displaystyle O(1)}的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后 挪位,为最新元素提供插入空间。
void insertion_sort(int arr[], int len){ int i,j,temp; for (i=1;i<len;i++){ temp = arr[i]; for (j=i;j>0 && arr[j-1]>temp;j--) arr[j] = arr[j-1]; arr[j] = temp; } }
希尔排序 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位
void shell_sort(int arr[], int len) { int gap, i, j; int temp; for (gap = len >> 1; gap > 0; gap = gap >> 1) for (i = gap; i < len; i++) { temp = arr[i]; for (j = i - gap; j >= 0 && arr[j] > temp; j -= gap) arr[j + gap] = arr[j]; arr[j + gap] = temp; } }
归并排序 把数据分为两段,从两段中逐个选最小的元素移入新数据段的末尾。 可从上到下或从下到上进行。