
C语言基础
提示
由于C语言范围较广,完全掌握C语言是非常困难的。从实际工程出发,本栏中的C语言只针对在STM32学习中必须知道的进行说明。
本栏中的c语言适合STM32CubeIDE,其中部分内容与课堂上讲的c语言可能有所不同。
数据类型
在c语言中,最先接触到的是变量,下面内容是对不同种的变量进行解释,及介绍用法。
基本类型
下面介绍的是一些常用的变量类型,在使用下面变量时需要注意变量允许赋值的范围,避免造成数据溢出,由于数据溢出导致的问题,有时很难会被发现。在定义变量时,需要考虑好使用什么类型的变量。
int a = 10; // 整型
float b = 5.5; // 浮点型
double c = 10.5; // 双精度浮点型
char d = 'A'; // 字符型
- int(整型)
- 范围:-2,147,483,648 到 2,147,483,647
- 说明:占用4字节。
- float(浮点型)
- 范围:约 -3.4E+38 到 3.4E+38,精度约6位小数
- 说明:占用4字节。
- double(双精度浮点型)
- 范围:约 -1.7E+308 到 1.7E+308,精度约15位小数
- 说明:占用8字节。
- char(字符型)
- 范围:-128 到 127(有符号),0 到 255(无符号)
- 说明:占用1字节。
无符号类型
unsigned int e = 20;
unsigned char f = 0xFF;
- unsigned int
- 范围:0 到 4,294,967,295
- 说明:占用4字节。
- unsigned char
- 范围:0 到 255
- 说明:占用1字节。
特定位宽类型
需要stdint.h
头文件,在STM32CubeIDE生成的工程中,不需要手动添加此头文件。
特定位宽类型是在STM32中最常用的变量,在以前的c语言学习中,常用的是基本类型和无符号整型。
int8_t g = -128; // 8位有符号整型
uint8_t h = 255; // 8位无符号整型
int16_t i = -32768; // 16位有符号整型
uint16_t j = 65535; // 16位无符号整型
int32_t k = -2147483648; // 32位有符号整型
uint32_t l = 4294967295U; // 32位无符号整型
- int8_t
- 范围:-128 到 127
- 说明:占用1字节。
- uint8_t
- 范围:0 到 255
- 说明:占用1字节。
- int16_t
- 范围:-32,768 到 32,767
- 说明:占用2字节。
- uint16_t
- 范围:0 到 65,535
- 说明:占用2字节。
- int32_t
- 范围:-2,147,483,648 到 2,147,483,647
- 说明:占用4字节。
- uint32_t
- 范围:0 到 4,294,967,295
- 说明:占用4字节。
数组
- 定义和初始化
int arr[5]; // 定义一个包含5个整数的数组,未初始化
int arr2[5] = {1, 2, 3, 4, 5}; // 定义并初始化
- 访问数组元素
int value = arr2[2]; // 获取数组的第三个元素,值为3
arr2[4] = 10; // 修改数组的第五个元素为10
- 数组遍历
for (int i = 0; i < 5; i++) {
printf("%d ", arr2[i]);
}
字符串
在C语言中,字符串实际上是一个以'\0'结尾的字符数组。
- 定义和初始化
char str1[] = "Hello"; // 字符串字面值自动添加'\0'
char str2[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; // 手动初始化
- 字符串操作函数(需要包含<string.h>头文件)
#include <string.h>
char str3[20];
strcpy(str3, str1); // 复制字符串
strcat(str3, " World"); // 连接字符串
int len = strlen(str3); // 获取字符串长度
数组与字符串的区别
在使用数组和字符串的时候,可能会出现疑问,这两个之间有什么区别,表面上都是使用一个变量存储多个值。下面来区分一下两者的区别。
数组
是一个具有相同类型元素的集合。数组的元素通过索引访问,并且数组的大小在定义时就确定了。
- 数组中元素类型相同。
- 大小在定义时确定且不可变。
- 可以存储任何数据类型(int、float、char等)。
- 没有特殊的结束标志。
字符串
在C语言中是一个以'\0'(空字符)结尾的字符数组。这个空字符用来标记字符串的结束。
- 实际上是一个字符数组。
- 以'\0'结尾,这个空字符标志着字符串的结束。
- 可以使用C标准库中的字符串处理函数(如strcpy、strlen等)。
- 通常用于处理文本数据。
最主要的区别是两者的操作方法是不同的,数组主要是针对某一位的操作,而字符串主要针对的是整体的操作。
如果字符串是以字符数组的形式定义并初始化的,可以直接修改其中的字符。如果字符串是以字符串字面值的形式定义的,是不可修改的。
char *str = "Hello";
str[1] = 'a'; // 这种修改是未定义行为
char str[] = "Hello";
str[5] = '!'; // 错误,破坏了'\0'
注意
在STM32中,通常使用数组存储数据,原因是可以快速的访问和修改某一位的值。通常采用char str[] = "Hello";
这种定义方式。
结构体
使用struct关键字定义结构体
struct Person {
char name[50];
int age;
float height;
};
结构体的使用方法
#include <stdio.h>
#include <string.h>
int main() {
struct Person person1 = {"Alice", 30, 5.7};//定义时初始化
struct Person person2;
strcpy(person2.name, "Bob");//定义后初始化
person2.age = 25;//访问结构体成员
person2.height = 5.9;
printf("Person 1: %s, %d, %.1f\n", person1.name, person1.age, person1.height);
printf("Person 2: %s, %d, %.1f\n", person2.name, person2.age, person2.height);
return 0;
}
#include <stdio.h>
#include <string.h>
struct Person {
char name[50];
int age;
float height;
};
int main() {
struct Person person = {"Alice", 30, 5.7};
struct Person *pPerson = &person;
printf("Name: %s\n", pPerson->name);
printf("Age: %d\n", pPerson->age);
printf("Height: %.1f\n", pPerson->height);
// 修改结构体成员
strcpy(pPerson->name, "Eve");
pPerson->age = 35;
pPerson->height = 6.0;
printf("Updated Name: %s\n", pPerson->name);
printf("Updated Age: %d\n", pPerson->age);
printf("Updated Height: %.1f\n", pPerson->height);
return 0;
}
if语法
int a = 10;
if (a > 5) {
// 条件为真时执行
} else if (a == 5) {
// 其他条件为真时执行
} else {
// 以上条件都不成立时执行
}
for
for (int i = 0; i < 10; i++) {
// 循环体
}
while
int i = 0;
while (i < 10) {
// 循环体
i++;
}
在stm32中存在主循环的概念,在系统运行时,所执行的程序是循环执行的,通常使用while(1)
来实现,while(1)
也是死循环。
指针
定义和使用指针
int a = 10;
int *p = &a; // 指针p指向变量a的地址
int b = *p; // 通过指针p获取变量a的值
指针运算
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr; // 指向数组的第一个元素
for (int i = 0; i < 5; i++) {
printf("%d ", *(p + i)); // 输出数组元素
}
指向指针的指针
int a = 10;
int *p = &a;
int **pp = &p; // 指向指针p的指针
printf("%d", **pp); // 输出10