一、基本数据类型
基本数据类型包括整型(int)、短整型(short)、长整型(long)、字符型(char)、浮点型(float)和双精度浮点型(double)。
类型定义方式(示例)取值范围整型(int)int a = 10;-2,147,483,648 ~ 2,147,483,647(4字节)短整型(short)short b = 20;-32,768 ~ 32,767(2字节)长整型(long)long c = 1723710; -2,147,483,648 ~ 2,147,483,647(4字节)字符型(char)char s = 'b';-128~127(1字节)浮点型(float)
float a = 10.1882;
1.2E-38 ~ 3.4E+38(4字节,精确小数点后六位)双精度浮点型(double)
double b = 298.18828323241;
2.3E-308 ~ 1.7E+308(8字节,小数点后15位)
二、构造数据类型
2.1.数组
数组是一种用于存储多个同类型数据元素的线性数据结构,以下是C语言数组的一些基本特点和用法:
2.1.1定义数组:
一般格式:data_type array_name[array_size];
其中data_type是基本数据类型,array_size是所需要构造的数组容量,如定义一个长度为三且全是整形的数组:
int arr1[3]; //当未指定初始值时,默认的初始值是0,即{0, 0, 0}。
2.1.2 初始化数组
数组可以在定义时进行初始化,也可以在后续赋值。初始化时可以在大括号内列出元素:
int numbers[5] = {1, 2, 3, 4, 5};
也可以部分初始化,未初始化的元素会被设置为0:
int numbers[5] = {1, 2}; // numbers[2]、numbers[3]、numbers[4] 被初始化为0
2.1.3 访问和修改数组元素
数组的元素通过索引访问,索引从0开始。例如:
int first = numbers[0]; // 访问第一个元素
numbers[1] = 10; // 修改第二个元素
2.1.4 数组的大小
在C语言中,数组的大小是固定的。一旦定义,大小就是不可改变的。可以通过使用sizeof运算符来获取数组所占的字节数:
int size = sizeof(numbers) / sizeof(numbers[0]); // 计算数组元素个数
但是当你传递一个二维数组到函数时,sizeof(arr) 在计算时将返回数组指针的大小,而不是数组的实际元素数量。
2.1.5 多维数组
C语言支持多维数组,最常用的是二维数组。定义方式如下:
data_type array_name[size1][size2];
2.1.6简单示例
#include
int main(){
int numbers[5] = {1, 2, 3, 4, 5};
int arr[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}; // 定义数组
// 输出数组元素
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
// 修改数组元素
numbers[2] = 10;
// 输出修改后的数组
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3; j++){
printf("%d\n", arr[i][j]); // 循环打印二维数组的内容
}
}
return 0;
}
2.2结构体
C语言中的结构体(struct)是用户定义的数据类型,可以将不同类型的数据组合成一个单一的类型。类似于python中的类、java中的对象。结构体使得程序员可以以更实用的方式组织和管理数据,尤其是在处理复杂数据时。
2.2.1 定义结构体
结构体的定义使用struct关键字,基本语法如下:
struct struct_name {
data_type member1;
data_type member2;
// ...
};
例如,定义一个表示学生的结构体:
struct student{
char name[20];
int age;
float score;
};
2.2.2. 声明结构体变量
定义结构体后,可以声明结构体变量。可以使用定义的结构体类型来创建新的变量:
struct Student Jake;
2.2.3. 初始化结构体
可以在声明结构体变量时进行初始化:
struct Student Jake = {"Jake", 20, 89.5};
或者可以在之后逐个成员地赋值:
struct Student stu1;
strcpy(stu1.name, "Bob"); // 需要包含
stu1.age = 21;
stu1.score = 90.0;
2.2.4. 访问结构体成员
使用点运算符(.)来访问结构体的成员:
printf("Name: %s\n", stu1.name);
printf("Age: %d\n", stu1.age);
printf("score: %.2f\n", stu1.grade);
2.2.5. 数组与结构体结合
可以创建结构体数组,以便存储多个结构体实例。例如,存储多个学生的信息:
struct Student students[3] = {
{"Alice", 20, 89.5},
{"Bob", 21, 90.0},
{"Charlie", 19, 85.0}
};
2.2.6. 结构体嵌套
结构体可以嵌套定义,即一个结构体的成员可以是另一个结构体:
struct Address {
char city[50];
char state[50];
};
struct Student {
char name[50];
int age;
float grade;
struct Address address; // 嵌套结构体
};
2.2.7.与typedef一起用:
可以为结构体定义新的别名,简化结构体的使用:
struct Student {
char name[50];
int age;
float grade;
};
// 使用 typedef 定义结构体的别名
typedef struct Student Student;
int main() {
// 使用 Student 而不是 struct Student
Student student1;
strcpy(student1.name, "Alice");
student1.age = 20;
student1.grade = 89.5;
printf("Name: %s, Age: %d, Grade: %.2f\n", student1.name, student1.age, student1.grade);
return 0;
}
三、指针类型
指针是一个变量,其值是另一变量的地址。简单来说,指针“指向”内存中的某个位置。所有类型的指针都有自己的类型,指针的类型决定了它所指向的数据的类型。3.1 声明指针
指针的声明使用星号(*)符号:
int *a; /* 一个整型的指针 */
double *b; /* 一个 double 型的指针 */
float *c; /* 一个浮点型的指针 */
char *d; /* 一个字符型的指针 */
3.2 初始化指针
可以使用取地址运算符(&)来初始化指针,该运算符用于获取变量的地址:
int a = 10;
int *p = &a; // p 现在指向变量 a 的地址
未初始化的指针会指向随机地址,使用它们会导致未定义行为。
3.3. 指针的基本操作
访问指针指向的值:
int b = *p; // b 现在是 10,*p 解引用 p,得到 a 的值
修改指针指向的值,可通过直接修改指针:
*p = 20; // 现在 a 的值变为 20
3.4. 指针与数组
C语言中,数组名代表数组的首地址,因此可以用指针来访问数组元素:
int arr[3] = {10, 20, 30};
int *p = arr; // 指向数组的第一个元素,数组名为地址,无需使用&即可赋值给*p
printf("%d\n", *(p + 1)); // 访问第二个元素,输出 20
printf("%d\n", p[1]); // 与上面等价,p[1]表示偏移量为1,p为数组的首地址可以看作数组名来调用数组
3.5. 指针与函数
指针可以作为函数参数进行传递,这样可以直接修改函数外部的变量:
void increment(int *p) {
(*p)++; // 解引用并自增
}
int main() {
int a = 5;
increment(&a); // 将 a 的地址传递给函数
printf("%d\n", a); // 输出 6
return 0;
}
3.6. 指向指针的指针
C语言允许指针指向指针,指针也有地址,这被称为“指向指针的指针”。这是多重指针的概念。
int a = 10;
int *p = &a; // 指向整型的指针
int **q = &p; // 指向指针的指针
printf("%d\n", **q); // 输出 10
3.7. 空指针
空指针是指不指向任何有效地址的指针。在C语言中,可以使用 NULL 来表示空指针:
int *p = NULL; // p 是一个空指针
使用空指针可以避免指针指向不确定的内存。
3.8. 动态内存分配
指针在动态内存分配(如使用 malloc)时非常有用。可以在运行时分配内存:
#include
#include
int main() {
int *arr = (int *)malloc(5 * sizeof(int)); // 分配 5 个整数的内存
if (arr == NULL) {
printf("Memory allocation failed!\n");
return 1;
}
for (int i = 0; i < 5; i++) {
arr[i] = i * 2; // 使用指针访问数组元素
}
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]); // 输出 0 2 4 6 8
}
free(arr); // 释放动态分配的内存
return 0;
}
动态分配的内存必须通过 free() 函数释放,以避免内存泄漏。
四、空类型void
在C语言中,void 是一个特殊的数据类型,表示“无类型”或“空类型”。它的使用主要包括函数的返回类型、指针类型及其作为不带参数的函数。下面是对 void 类型的详细介绍:
1. void 作为函数的返回类型
当一个函数不需要返回任何值时,可以将其返回类型声明为 void:
void printMessage() {
printf("Hello, World!\n");
}
int main() {
printMessage(); // 调用不返回任何值的函数
return 0;
}
2. void 指针
void 类型也可以用作指针类型,称为“空指针”。void 指针可以指向任何类型的数据,但不能直接解引用,因为编译器无法确定其所指向数据的类型。
void *ptr; // 声明一个 void 指针
int num = 42;
ptr = # // 将 int 类型的地址赋给 void 指针
// 使用 void 指针之前需要转换为具体类型
int value = *(int *)ptr; // 强制类型转换为 int 指针并解引用
printf("%d\n", value); // 输出 42
void指针在动态内存管理中非常常用,例如,malloc函数的返回值就是void*类型。
3. 不带参数的函数
在C语言中,定义不带参数的函数时,可以使用 void 来显式地表示函数不接收参数:
void noParameters(void) {
printf("This function takes no parameters.\n");
}
接下来是输入输出内容:
一、格式化输入输出函数
1.标准输入函数scanf
scanf 是 C 语言中用于从标准输入(通常是键盘)读取数据的函数。它是 C 标准库的一部分,声明在头文件
1.1基本语法
int scanf(const char *format, ...);
format:一个格式字符串,指定输入数据的格式。...:一个可变参数列表,参数的数量和类型根据格式字符串的内容而定。scanf 函数的返回值是成功读取的项数(根据格式字符串中指定的转换说明符的数量)。如果在读取过程中发生错误,或者到达文件末尾(在读取文件时),则返回一个 EOF(通常为 -1)。1.2. 格式字符串
格式字符串包含文本和格式指示符。常见的格式指示符包括:
%d:读取整数(十进制)。%f:读取浮点数(单精度)。%lf:读取双精度浮点数(double)。%c:读取单个字符。%s:读取字符串(空格作为分隔符)。%u:读取无符号整数。%x:读取十六进制整数。格式字符串可以包括多个格式指示符,用空格、换行或其他分隔符分隔。
1.3示例
读取字符串、整数和浮点数:
#include
int main() {
char name[4];
int age;
float height;
printf("Enter your name: ");
scanf("%s", &name); // 读取字符串
printf("Enter your age: ");
scanf("%d", &age); // 读取整数
printf("Enter your height (in meters): ");
scanf("%f", &height); // 读取浮点数
printf("%s are %d years old and %.2f meters tall.\n", name, age, height);
return 0;
}
1.4 注意事项
输入缓冲区问题:scanf 在读取字符串时会在遇到空格、换行等空白字符时停止,因此如果需要读取包含空格的字符串,应使用 fgets 函数。
地址运算符:对于大多数数据类型(如 int、float),需要在变量前加上地址运算符 & 来获取变量的地址。然而,对于数组(字符串)和指针类型的变量,就不需要添加地址运算符,因为数组名本身就是指向其第一个元素的指针。
格式匹配:scanf 在输入时会进行格式匹配,如果用户输入的格式与格式说明符不匹配,scanf 可能会导致未定义行为。在使用 scanf 进行输入时,最好检查返回值来确保输入成功。
2.格式化输出函数printf
printf 是 C 语言中用于向标准输出设备(通常是屏幕)格式化输出数据的函数。它是 C 标准库的一部分,声明在头文件
2.1.基本语法
printf(String, list ...);
String:一个格式控制字符串,指定输出数据的类型和格式。list:输出列表...:一个可变参数列表,参数的数量和类型根据格式字符串的内容而定。返回值是函数的返回值是成功输出的字符总数。如果输出失败,则返回一个负值。printf("a=%d, b=%f", a, b);
表示a按照整型格式输出,b按照浮点数格式输出。
2.2.格式字符串
格式字符串包含文本和格式指示符。常见的格式指示符包括:
%d:输出整数(十进制)。
%f:输出浮点数(单精度)。
%lf:输出双精度浮点数(double)。
%c:输出单个字符。
%s:输出字符串(空格作为分隔符)。
%u:输出无符号整数。
%o:输出八进制整数。
%x:输出十六进制整数。
%%:输出一个百分号字符。浮点数输出时可以控制数据长度和精度:%m.nf,其中m表示数据长度,n表示小数点后保留几位。
例子:
#include
int main() {
int age = 25;
float height = 1.75;
printf("Age: %d years\n", age); // 输出整数
printf("Height: %2.1f meters\n", height); // 输出浮点数,保留一位小数
return 0;
}
2.3. 格式控制
printf 的格式字符串可以包含额外的控制选项:
对齐:默认为右对齐,可以通过在宽度前加 - 来实现左对齐。例如:%-10d 表示一个宽度为 10 的整数,左对齐。
宽度:可以指定输出的最小宽度。例如,%5d 表示至少 5 个字符宽的输出。
精度:特定于浮点数和字符串。例如,%.2f 表示输出浮点数时保留两位小数,%.5s 表示输出字符串的前 5 个字符。
填充:也可以通过指定宽度时添加 0 来做填充,比如 %05d 表示用 0 填充宽度为 5 的整数。
二、字符串输入输出函数
1. puts 函数
puts 函数用于将字符串输出到标准输出(通常是屏幕),并在输出后自动添加一个换行符。
puts(const char *str);
str:指向要输出的字符串的指针。字符串应以空字符 \0 结尾。返回值为非负整数,表示成功输出的字符数(包括换行符)。如果输出失败,则返回 EOF。例:
#include
int main() {
const char *message = "Hello, World!";
puts(message); // 输出 "Hello, World!" 并换行
return 0;
}
2. gets 函数(不推荐使用)
gets 函数用于从标准输入中读取一行字符串,直到遇到换行符(即用户按下 Enter 键)。然而,由于 gets 没有边界检查,容易导致缓冲区溢出,因此在 C11 标准中被声明为已废弃,不推荐使用。
char *gets(char *str);
str:指向字符数组的指针,用于存储读取的字符串。如果读取成功,返回指向字符串的指针;如果发生读取错误或到达文件结束标志,则返回 NULL。例:
#include
int main() {
char name[100];
puts("Enter your name:");
gets(name); // 从标准输入读取字符串
puts("Hello, ");
puts(name); // 输出读取的字符串
return 0;
}
3. 使用 fgets 作为 gets 的替代
由于 gets 的安全性问题,推荐使用 fgets 函数作为字符串输入的替代方法。fgets 可以指定读取的最大字符数,从而避免缓冲区溢出。
char *fgets(char *str, int n, FILE *stream);
str:指向字符数组的指针,用于存储读取的字符串。n:要读取的最大字符数,包括末尾的空字符。stream:输入流,通常是 stdin,表示从标准输入(通常是键盘)读取数据。成功时返回 str,失败时返回 NULL。例:
#include
int main() {
char name[100];
puts("Enter your name:");
fgets(name, sizeof(name), stdin); // 安全地从标准输入读取字符串
puts("Hello, ");
puts(name); // 输出读取的字符串
return 0;
}
三、字符输入输出函数
1. getchar 函数
getchar 用于从标准输入流中读取一个字符。
getchar(void);
返回读取到的字符(作为 int 类型)。如果到达文件末尾(EOF)或发生错误,则返回 EOF(通常为 -1)。2. putchar 函数
putchar 用于向标准输出流写入一个字符。
putchar(int ch);
ch:要输出的字符,虽然参数类型为 int,但其对应一个字符。返回输出的字符。如果发生错误,则返回 EOF。
例:
#include
int main() {
char ch;
printf("请输入一个字符: ");
ch = getchar(); // 从标准输入读取一个字符
printf("您输入的字符是: ");
putchar(ch); // 输出读取的字符
putchar('\n'); // 换行
printf("输出字符: ");
putchar(ch); // 输出字符 'A'
putchar('\n'); // 换行
return 0;
}