目录
函数和程序结构:
函数的定义和调用:
函数的参数传递方式(按值传递,按引用传递)
局部变量和全局变量
头文件和库函数的使用
数组和字符串
一维数组的定义和使用
二维数组的定义和使用
字符串的定义和使用
字符串处理函数
在C语言中,函数是程序的基本组成单元。函数用于封装可重用的代码块,并通过调用函数来执行特定的任务。每个C程序至少包含一个名为
main
的函数,该函数作为程序的入口点。下面是一个简单的C语言程序的结构,以及函数的声明和定义示例:
// 预处理指令:包含其他头文件和宏定义等 #include
// 函数声明(函数原型) int add(int a, int b); // main函数:程序的入口点 int main() { // 变量声明和初始化 int num1 = 10; int num2 = 20; int sum; // 函数调用 sum = add(num1, num2); // 输出结果 printf("Sum: %d\n", sum); return 0; } // 函数定义 int add(int a, int b) { return a + b; } 上述示例程序的结构如下:
第一行是预处理指令,用于包含其他头文件和宏定义等。
紧接着是函数的声明或函数原型。函数原型指定了函数的名称、参数类型和返回值类型,以便在程序的其他位置使用该函数。
main
函数是程序的入口点。它不接受任何参数,并且必须返回一个整数值(通常为int
类型)。在main
函数中,你可以声明和初始化变量,调用其他函数,执行任务,并输出结果。在
main
函数之后是其他函数的定义。函数定义包括函数的返回类型、函数名和参数列表,以及函数体中的代码。在示例中,add
函数计算两个整数的和。程序使用了
printf
函数来输出结果。printf
是C语言标准库提供的一个函数,用于在控制台输出文本。注意事项:
- 函数之间的顺序是无关紧要的,但如果在使用函数之前没有进行函数声明或定义,则需要在使用之前提前进行声明。
- 函数可以有参数(输入)和返回值(输出),也可以没有参数或返回值。
- C语言中的变量必须在使用之前声明并初始化。
函数的定义: 函数的定义包括函数的返回类型、函数名、参数列表以及函数体的代码实现。函数定义告诉编译器如何执行特定任务。
返回类型 函数名(参数列表) { // 函数体代码 // 执行特定任务 return 返回值; }
示例:
// 函数的定义 int add(int a, int b) { int sum = a + b; return sum; }
在上述示例中,
add
函数的定义具有返回类型int
,函数名称为add
,参数列表为(int a, int b)
。函数体内部计算两个整数的和并将结果作为返回值。函数的调用: 调用函数即使用函数的名称及其参数来执行函数体内部的代码,并获取函数的返回值(如果有返回值)。
返回类型 变量名 = 函数名(参数列表);
示例:
// 函数的调用 int result = add(3, 4);
在上述示例中,我们调用了之前定义的
add
函数,将参数3
和4
传递给函数,并将返回的结果保存在result
变量中。函数的定义和调用使得我们能够封装和重用代码,从而提高代码的可读性、维护性和模块化程度。
需要注意的几点:
- 函数的名称应该唯一,不能与其他变量或函数重名。
- 调用函数时,传递给函数的参数应与函数定义中的参数类型、数量和顺序相匹配。
- 如果函数没有返回值,则函数的返回类型应为
void
,不需要在调用时将返回值赋给任何变量。
在C语言中,函数的参数传递方式可以是按值传递(pass-by-value)或按引用传递(pass-by-reference)。
按值传递(pass-by-value): 在按值传递中,函数接收参数的副本,而不是原始的数据。在函数内部对参数的修改不会影响到函数外部的原始数据。
示例:
void square(int num) { num = num * num; } int main() { int x = 5; square(x); printf("x: %d\n", x); // 输出:x: 5 return 0; }
在上述示例中,
square
函数接收一个整数参数,并在函数内部将其平方。然而,对num
的修改只是在函数内部生效,并不影响main
函数中的变量x
。按引用传递(pass-by-reference): 在按引用传递中,函数接收参数的引用或指针,可以直接操作原始数据。在函数内部对参数的修改也会影响到函数外部的原始数据。
示范:
void square(int* numPtr) { *numPtr = (*numPtr) * (*numPtr); } int main() { int x = 5; square(&x); printf("x: %d\n", x); // 输出:x: 25 return 0; }
在上述示例中,
square
函数接收一个整数指针参数numPtr
,通过解引用该指针并修改指向的内存中的值来实现参数的平方。这样在main
函数中调用square
函数后,x
的值也被修改为25。需要注意的是,按引用传递需要使用指针来处理参数,而且要小心处理指针为空的情况。
总结:
- 按值传递将参数的副本传递给函数,对参数的修改不会影响原始数据。
- 按引用传递将参数的引用或指针传递给函数,可以直接操作原始数据,对参数的修改会影响到原始数据。
根据需要选择合适的传递方式,在一般情况下,按值传递是常用的方式。如果想通过函数修改原始数据,可以使用指针进行按引用传递。
在C语言中,局部变量(local variable)和全局变量(global variable)是两种不同的变量类型,它们具有以下特点:
局部变量:
- 局部变量定义在函数内部或一个代码块内部,只在其所在的函数或代码块内可见。
- 局部变量在其所在的函数或代码块执行结束后会被销毁。
- 局部变量的作用域(scope)限定在定义它的函数或代码块内部,外部的函数或代码块无法访问它。
示例:
void foo() { int x = 5; // 局部变量x printf("x: %d\n", x); } int main() { foo(); // 调用foo函数 // printf("%d\n", x); // 错误:无法访问局部变量x return 0; }
在上述示例中,
x
是foo()
函数内部的局部变量。它只能在foo()
函数内部使用,对于main()
函数来说是不可见的。全局变量:
- 全局变量定义在函数之外,可以被程序中的所有函数访问。
- 全局变量的作用域跨越整个程序,从定义它的位置开始,直到程序结束。
- 全局变量的生命周期与整个程序的运行时间相同,即在程序启动时创建,在程序结束时销毁。
示例:
int globalVar = 10; // 全局变量 void foo() { printf("globalVar: %d\n", globalVar); } int main() { foo(); // 调用foo函数访问全局变量globalVar printf("globalVar: %d\n", globalVar); // 在main函数中也可以访问全局变量 return 0; }
头文件(Header Files):
- 头文件通常包含函数声明、宏定义、类型定义和结构声明等信息。
- 头文件的扩展名为
.h
,例如stdio.h
、stdlib.h
等。- 头文件通过
#include
预处理指令引入到源代码文件中。- 引入头文件可以让源代码文件访问到头文件中声明的函数、变量和类型。
示例:
// header.h 头文件 #ifndef HEADER_H // 防止头文件重复包含 #define HEADER_H // 声明函数 int add(int a, int b); #endif // main.c 源代码文件 #include
#include "header.h" // 引入自定义的头文件 int main() { int result = add(3, 4); // 使用头文件中声明的函数 printf("Result: %d\n", result); return 0; }
在上述示例中,
header.h
是自定义的头文件,其中声明了一个add
函数。在main.c
源代码文件中通过#include "header.h"
引入了该头文件,并可以在main
函数中调用add
函数。库函数(Library Functions):
- 库函数是一组预定义好的函数,提供了各种通用的功能,如字符串处理、数学运算、文件操作等。
- 库函数以函数的形式存在于库文件中,可以被多个程序共享使用。
- 库函数通常是封装好的二进制代码,通过链接(linking)将其与程序一起编译。
- 在C语言中,常见的标准库函数位于标准库(Standard Library),如
stdio.h
、stdlib.h
、math.h
等。示例:
#include
#include int main() { double x = 2.5; double result = sqrt(x); // 使用库函数sqrt计算平方根 printf("Square root of %.1lf is %.2lf\n", x, result); return 0; } 在上述示例中,通过
#include
引入了数学库函数的头文件,然后在main
函数中使用sqrt
函数计算给定数字的平方根。需要注意的是,在使用库函数时,有时需要链接相应的库文件。对于标准库函数,编译器通常会自动链接相应的库文件。对于其他库函数,可能需要手动指定链接选项来告诉编译器使用哪个库文件。
定义一维数组:
- 一维数组的定义格式是:
数据类型 数组名[数组长度];
- 数组类型可以是任意合法的数据类型,如整型、字符型、浮点型等。
- 数组名是标识符,用于标识该数组,在程序中唯一标识该数组。
- 数组长度是一个非负整数,指定了数组可以容纳的元素个数。
示例:
int numbers[5]; // 定义一个包含5个整数的数组 float grades[10]; // 定义一个包含10个浮点数的数组 char characters[100]; // 定义一个包含100个字符的数组
访问和操作一维数组的元素:
- 一维数组的元素可以通过索引来访问和操作,索引从0开始,到数组长度减1结束。
- 通过数组名和索引,可以读取或修改数组元素的值。
示例:
int numbers[5] = {1, 2, 3, 4, 5}; // 初始化整型数组 int firstElement = numbers[0]; // 读取第一个元素 numbers[2] = 10; // 修改第三个元素的值 float average = (numbers[1] + numbers[3]) / 2.0; // 使用数组元素进行计算
在上述示例中,我们定义了一个整型数组
numbers
,并对其进行初始化。然后通过索引读取和修改数组中的元素。另外,我们还可以使用数组元素进行其他的计算。需要注意的是,数组索引越界会导致未定义的行为,确保在访问数组元素时不超出数组范围。
定义二维数组:
- 二维数组的定义格式是:
数据类型 数组名[行数][列数];
- 行数和列数是非负整数,分别指定了二维数组的行数和列数。
- 数据类型可以是任意合法的数据类型,如整型、字符型、浮点型等。
示例:
int matrix[3][4]; // 定义一个3行4列的整型二维数组 float table[2][5]; // 定义一个2行5列的浮点型二维数组 char chessboard[8][8]; // 定义一个8行8列的字符型二维数组
访问和操作二维数组的元素:
- 二维数组的元素可以通过行索引和列索引来访问和操作。
- 行索引和列索引都从0开始,到对应的行数和列数减1结束。
- 通过数组名、行索引和列索引,可以读取或修改数组元素的值。
示例:
int matrix[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; // 初始化整型二维数组 int firstElement = matrix[0][0]; // 读取左上角元素 matrix[1][2] = 15; // 修改第二行第三列的元素值 float average = (matrix[0][1] + matrix[2][3]) / 2.0; // 使用数组元素进行计算
在上述示例中,我们定义了一个整型二维数组
matrix
,并对其进行了初始化。然后通过行索引和列索引,读取和修改数组中的元素。另外,我们还可以使用数组元素进行其他的计算。
定义字符串:
- 字符串的定义格式是:
char 字符数组名[数组长度] = "字符串内容";
- 字符数组名是标识符,用于标识该字符串,在程序中唯一标识该字符串。
- 数组长度是一个非负整数,指定了字符数组的最大容量,应该至少比字符串内容的长度多1个字节(用于存储空字符)。
示例:
char greeting[20] = "Hello, world!"; // 定义一个包含20个字符的字符串 char name[] = "John"; // 自动确定数组长度,足够存储字符内容和空字符
访问和操作字符串:
- 可以通过数组名和索引来访问和操作字符串中的字符。
- 字符串中的每个字符都有一个对应的索引,从0开始,到字符串长度减1结束。
- 可以通过循环遍历字符串中的字符,或使用各种字符串处理函数来进行操作。
示例:
char greeting[20] = "Hello, world!"; char firstChar = greeting[0]; // 读取第一个字符 greeting[7] = 'W'; // 修改第8个字符为大写 int length = strlen(greeting); // 获取字符串长度 int compareResult = strcmp(greeting, "Hi"); // 比较字符串 printf("%s\n", greeting); // 输出字符串内容
在上述示例中,我们定义了一个字符数组
greeting
作为字符串,并对其进行初始化。然后通过索引读取和修改字符串中的字符。另外,通过调用字符串处理函数strlen
获取字符串长度,strcmp
比较字符串内容。最后使用printf
函数输出字符串内容。需要注意的是,在使用字符串时要确保不越界,并且为字符串留出足够的容量存储空字符。
在C语言中,有一些常用的字符串处理函数可以帮助我们进行字符串操作和处理。下面我列举一些常见的字符串处理函数及其功能:
strlen
:计算字符串的长度。#include
size_t strlen(const char *str);
strcpy
:将一个字符串复制到另一个字符串中。#include
char *strcpy(char *dest, const char *src);
strcat
:将一个字符串拼接到另一个字符串的末尾。#include
char *strcat(char *dest, const char *src);
strcmp
:比较两个字符串的大小。#include
int strcmp(const char *str1, const char *str2);
strstr
:在一个字符串中搜索指定子串的出现位置。#include
char *strstr(const char *str, const char *substr);
strtok
:将一个字符串分割为多个子串#include
char *strtok(char *str, const char *delimiters); 这些只是一些常见的字符串处理函数,还有其他更多的函数可供使用。这些函数的使用方法需要查看相应的函数文档,并且要确保在使用这些函数之前正确包含对应的头文件。