1、二维数组:
C语言中的数组是一种基本的数据结构,用于在计算机内存中连续存储相同类型的数据。
数组中的每个元素可以通过索引(或下标)来访问,索引通常是从0开始的。数组的大小在声明时确定,并且之后不能改变(除非使用动态内存分配技术,如指针和malloc/free等)。如果初始化时省略数组的大小,编译器会自动根据初始化列表中元素的数量确定数组的大小。
数组索引越界是C语言中常见的错误。如果尝试访问数组边界之外的元素,程序会崩溃或产生不可预测的行为。
数组的大小在编译时确定,且固定不变。如果需要动态改变数组大小,应考虑使用指针和动态内存分配。
数组名在表达式中通常被当作指向数组首元素的指针。但是,数组名本身并不是一个指针变量,而是一个常量表达式,其值为数组首元素的地址。
测试代码1:
#include <stdio.h>
int main() {
// 定义一个6x3的二维数组并初始化
int arr[6][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{10, 11, 12},
{13, 14, 15},
{16, 17, 18}
};
// 遍历二维数组
for (int i = 0; i < 6; i++) { // 外层循环遍历行(i从0到5)
for (int j = 0; j < 3; j++) { // 内层循环遍历列(j从0到2)
// 打印当前元素的值及其下标
printf("arr[%d][%d] = %d\n", i, j, arr[i][j]);
}
}
return 0;
}
运行结果如下:
测试代码2:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 函数声明
void fillRandomArray(int arr[][8], int rows, int cols);
int searchArray(int arr[][8], int rows, int cols, int target);
int main() {
int arr[3][8]; // 定义一个3x8的二维数组
int target; // 需要查找的目标值
int result; // 查找结果
// 初始化随机数生成器
srand(time(NULL));
// 填充随机数到二维数组中
fillRandomArray(arr, 3, 8);
// 显示数组内容
printf("数组内容:\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 8; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
// 获取查找的目标值
printf("请输入要查找的目标值: ");
scanf("%d", &target);
// 在数组中查找目标值
result = searchArray(arr, 3, 8, target);
// 输出查找结果
if (result != -1) {
printf("找到目标值 %d 在位置 [%d][%d].\n", target, result / 8, result % 8);
} else {
printf("未找到目标值 %d.\n", target);
}
return 0;
}
// 填充随机数到二维数组中
void fillRandomArray(int arr[][8], int rows, int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
arr[i][j] = rand() % 100; // 随机数的范围是0到99
}
}
}
// 在二维数组中查找指定的数据
int searchArray(int arr[][8], int rows, int cols, int target) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (arr[i][j] == target) {
return i * cols + j; // 返回元素的线性索引,可以根据需要调整为返回行列索引
}
}
}
return -1; // 如果没有找到,返回-1
}
运行结果如下:
测试代码3:
#include <stdio.h>
#include <stdlib.h>
#define MAX_PER_LINE 10
int main() {
int n, i, j, countEven = 0;
printf("请输入整数的数量: ");
scanf("%d", &n);
// 使用malloc分别为原始整数数组和偶数数组动态分配内存
int *nums = (int *)malloc(n * sizeof(int));
int *evenNums = NULL;
// 读取整数
printf("请输入 %d 个整数:\n", n);
for (i = 0; i < n; i++) {
scanf("%d", &nums[i]);
}
// 计算偶数数量并分配偶数数组内存
for (i = 0; i < n; i++) {
if (nums[i] % 2 == 0) {
countEven++;
}
}
evenNums = (int *)malloc(countEven * sizeof(int));
// 分离偶数,遍历原始数组,将偶数存入另一个数组。
j = 0;
for (i = 0; i < n; i++) {
if (nums[i] % 2 == 0) {
evenNums[j++] = nums[i];
}
}
// 输出原始数组
printf("原始数组:\n");
for (i = 0; i < n; i++) {
printf("%d ", nums[i]);
if ((i + 1) % MAX_PER_LINE == 0) {
printf("\n");
}
}
// 输出偶数数组
printf("\n偶数数组:\n");
for (i = 0; i < countEven; i++) {
printf("%d ", evenNums[i]);
if ((i + 1) % MAX_PER_LINE == 0) {
printf("\n");
}
}
// free释放动态分配的内存。
free(nums);
free(evenNums);
return 0;
}
运行结果如下:
..........................................................................................................................................................
2、 字符数组:
测试代码:
#include <stdio.h>
#include <string.h>
int main() {
// 静态定义并初始化字符数组
// 编译器会自动为字符串字面量添加\0。
// 字符串在C语言中是通过字符数组实现的,但字符数组并不等同于字符串。
// 字符数组可以包含任何字符,包括\0,而字符串是以\0结尾的字符序列。
char str1[] = "Hello, Static Initialization!"; //自动添加'\0'
printf("Static Initialization: %s\n", str1);
char str2[13] = {'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '\0'}; // 显式添加'\0'
printf("%s\n", str2);
// 动态定义后逐个初始化字符数组(包括显式添加'\0')
char str3[50];
int i;
for(i = 0; i < 26; i++) {
str3[i] = 'A' + i; // 使用ASCII码初始化大写字母A到Z
}
str3[i] = '\0'; // 显式添加字符串结束符
printf("Manual Initialization: %s\n", str3);
// 使用strcpy函数初始化字符数组
char str4[10];
strcpy(str3, "Hello, strcpy Initialization!");
printf("strcpy Initialization: %s\n", str4);
return 0;
}
运行结果如下:
测试代码2:
#include <stdio.h>
#include <string.h>
int main() {
int n = 5; // 有5个字符串要处理
char strs[n][100]; // 字符串数组,每个字符串最多99个字符加上一个'\0'
// 输入循环
printf("请输入%d个字符串(每个字符串后按Enter键):\n", n);
for (int i = 0; i < n; i++) {
fgets(strs[i], sizeof(strs[i]), stdin);
// strcspn(strs[i], "\n")函数用于找到strs[i]中第一个换行符(\n)的位置(如果不存在,则返回strs[i]的长度)。
// 然后将该位置上的字符替换为字符串终止符'\0',以移除可能由fgets()读取并存储的换行符。
// fgets读取换行符,fgets()会将换行符(如果它存在且缓冲区足够大)也读取到字符串中。
strs[i][strcspn(strs[i], "\n")] = 0;
}
// 输出循环
printf("你输入的字符串是:\n");
for (int i = 0; i < n; i++) {
printf("%s\n", strs[i]);
}
return 0;
}
运行结果如下:
...........................................................................................................................................................
3、 字符串处理函数:
处理字符串主要依赖于标准库 string.h,常用的字符串处理函数及其功能:
strlen(const char str)
功能:计算字符串 str 的长度(不包括结尾的空字符 '\0')。
返回值:返回字符串的长度。
strcpy(char dest, const char src)
功能:将字符串 src(包括终止的空字符)复制到字符串 dest 所指向的数组中。
返回值:返回 dest 的指针。
使用时要确保 dest 指向的数组有足够的空间来存放 src 字符串。
strncpy(char dest, const char src, size_t n)
功能:将字符串 src 的前 n 个字符复制到 dest 指向的数组中。如果 src 的长度小于 n,则在 dest 的剩余部分填充空字符。
返回值:返回 dest 的指针。
与 strcpy 不同,strncpy 不会自动添加终止的空字符,除非 src 的长度小于 n。
strcat(char dest, const char src)
功能:将字符串 src 连接到 dest 字符串的末尾,并包括 src 的终止空字符。
返回值:返回 dest 的指针。
使用时要确保 dest 指向的数组有足够的空间来存放结果字符串。
strncat(char dest, const char src, size_t n)
功能:将字符串 src 的前 n 个字符(不包括终止的空字符)连接到 dest 字符串的末尾。如果 src 的长度小于 n,则只连接 src 的内容,并且不会自动添加终止的空字符。
返回值:返回 dest 的指针。
strncat 不会添加终止的空字符,除非有足够的空间并且 src 的长度小于 n。
strcmp(const char str1, const char str2)
功能:比较字符串 str1 和 str2。
返回值:如果 str1 和 str2 字符串相等,则返回 0;如果 str1 在字典序上小于 str2,则返回负数;如果 str1 在字典序上大于 str2,则返回正数。
strncmp(const char str1, const char str2, size_t n)
功能:比较字符串 str1 和 str2 的前 n 个字符。
返回值:与 strcmp 相同,但只比较前 n 个字符。
strchr(const char str, int c)
功能:在字符串 str 中查找第一次出现的字符 c。
返回值:返回指向第一次出现的字符 c 的指针;如果未找到,则返回 NULL。
strrchr(const char str, int c)
功能:在字符串 str 中查找最后一次出现的字符 c。
返回值:与 strchr 类似,但查找方向相反。
strstr(const char str1, const char str2)
功能:在字符串 str1 中查找第一次出现的子串 str2。
返回值:如果找到,则返回指向 str1 中子串 str2 的第一个字符的指针;如果未找到,则返回 NULL。
测试代码1:
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "Hello, World!";
char str2[] = "World";
char dest[50];
char *found;
// strlen
printf("Length of '%s' is %zu\n", str1, strlen(str1));
// strcpy
strcpy(dest, str1);
printf("Copied string: '%s'\n", dest);
// strcat
strcat(dest, " Again!");
printf("Appended string: '%s'\n", dest);
// strcmp
if (strcmp(str1, "Hello, World!") == 0) {
printf("'%s' is equal to 'Hello, World!'\n", str1);
}
// strncmp
if (strncmp(str1, "Hello", 5) == 0) {
printf("'%s' starts with 'Hello'\n", str1);
}
// strchr
found = strchr(str1, ',');
if (found) {
printf("Found ',' at position: %ld\n", (long)(found - str1 + 1));
}
// strrchr
found = strrchr(str1, 'o');
if (found) {
printf("Last 'o' found at position: %ld\n", (long)(found - str1 + 1));
}
// strstr
found = strstr(str1, str2);
if (found) {
printf("'%s' found in '%s'\n", str2, str1);
}
// strncpy (不会添加空字符,除非有足够的空间)
char buffer[6];
strncpy(buffer, str1, 5);
buffer[5] = '\0'; // 手动添加空字符
printf("Copied first 5 characters: '%s'\n", buffer);
// strncat (假设dest有足够的空间)
char dest2[50] = "Start: ";
strncat(dest2, str1, 5); // 追加前5个字符
printf("Appended first 5 characters: '%s'\n", dest2);
return 0;
}
运行结果如下:
测试代码2:
#include <stdio.h>
#include <string.h>
#include <stdbool.h> // 使用bool
int countWords(const char *str) {
int count = 0;
//使用bool类型跟踪当前是否在处理一个单词。
bool inWord = false; // 标记当前是否在单词中。
// 遍历字符串中的每个字符
for (int i = 0; str[i] != '\0'; i++) {
// 如果当前字符不是空格且之前不在单词中,则开始一个新单词
if (str[i] != ' ' && !inWord) {
inWord = true;
count++;
}
// 如果当前字符是空格且之前在单词中,则结束当前单词
// 假设单词之间仅由空格分隔,并且不考虑标点符号作为单词的一部分。
// 如果需要更复杂的处理(例如,将标点符号视为单词的一部分或忽略某些特定的分隔符),需要调整逻辑以满足需求。
else if (str[i] == ' ' && inWord) {
inWord = false;
}
// 省略其他情况的实现,如:连续空格或字符串末尾
}
// 如果字符串以单词结束,则最后一个单词的计数会在循环中被增加
// 无需在循环外再次增加
return count;
}
int main() {
char text[1000]; // 输入的文本不超过999个字符
printf("请输入一段文字(不超过999个字符):");
fgets(text, sizeof(text), stdin); // 使用fgets,以避免溢出
// 去除fgets读取的换行符
size_t len = strlen(text);
if (len > 0 && text[len - 1] == '\n') {
text[len - 1] = '\0';
}
int wordCount = countWords(text);
printf("单词数量为:%d\n", wordCount);
return 0;
}
运行结果如下: