C语言基础(七)
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;
}
运行结果如下:
