概述
在C语言中,数组是一种数据结构,用于存储具有相同类型和连续内存地址的元素集合。数组中的每个元素可以通过索引(下标)访问,并且数组的大小在声明时就必须确定。
定义
数组是一系列相同类型的变量有序排列而成的数据集合。
特点
所有元素的类型相同。
元素在内存中是连续存储的。
访问数组元素通过索引完成,索引从0开始。
C99标准之前,数组长度必须为编译时常量;C99及以后允许在某些情况下使用变量作为数组长度创建变长数组(VLA)。
使用示例
声明与初始化
// 声明并初始化一个包含5个整数的数组
int arr[5] = {1, 2, 3, 4, 5};
// 或者仅声明而不初始化
int anotherArr[6];
•访问数组元素:// 访问数组的第一个元素(索引为0)
int firstElement = arr[0];
// 修改数组的第四个元素
arr[3] = 10;
一维数组
#include <stdio.h>
int main() {
int numbers[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; ++i) {
printf("Element at index %d is: %d\n", i, numbers[i]);
}
return 0;
}
多维数组
C语言还支持多维数组,例如二维数组,可以看作是一个矩阵:
int matrix[3][4]; // 3行4列的整型二维数组
// 初始化二维数组的一部分
matrix[0][0] = 1;
matrix[1][1] = 5;
matrix[2][3] = 9;
// 访问二维数组元素
printf("Element in the second row and third column: %d\n", matrix[1][2]);
注意事项
数组的索引不能越界,即对于长度为N的数组,有效索引范围是从0到N-1。
在C语言中没有内建的数组大小检查,程序员需要确保自己在操作数组时不会超出其边界。
动态数组
虽然C语言标准库不直接提供动态数组功能,但可以通过指针和malloc()、calloc()等动态内存分配函数来实现动态数组的功能。例如:
#include <stdio.h>
#include <stdlib.h>
int main() {
int size = 10; // 动态决定数组长度
int *dynamicArray = (int*) malloc(size * sizeof(int)); // 分配内存空间
if (dynamicArray == NULL) {
printf("Memory allocation failed.\n");
return 1;
}
dynamicArray[0] = 1;
// 使用和填充动态数组...
free(dynamicArray); // 不再使用时释放内存
return 0;
}
字符数组
在C语言中,字符数组是一种专门用来存储字符序列(即字符串)的数据结构。
字符数组是一个由char
类型元素组成的数组。
char str[10]; // 定义一个长度为10的字符数组
可以在声明时通过字符串字面量进行初始化,并且系统会自动添加终止符 \0
表示字符串结束。
char s1[] = {'h', 'e', 'l', 'l', 'o'};
char s2[] = "hello";
printf("s1 size: %lu\n", sizeof(s1)); // 5
printf("s2 size: %lu\n", sizeof(s2)); // 6
printf("s1 length: %lu\n", strlen(s1)); // 5 遇 \0 终止计算,这里 s1 没有 \0,所以可能访问非法内存
printf("s2 length: %lu\n", strlen(s2)); // 5 strlen 不会计算 \0
char s3[] = "hello\0world";
printf("s3 length: %lu\n", strlen(s3)); // 5
printf("s3 size: %lu\n", sizeof(s3)); // 12
所以在设置字符数组大小时要同时分配足够容纳字符串以及 \0
。
#include <stdio.h>
int main() {
// 声明并初始化一个字符数组
char name[20] = "Alice";
// 计算字符串长度
int length = strlen(name);
printf("Name length: %d\n", length);
// 输出整个字符串
printf("Name: %s\n", name);
// 修改字符数组的内容
name[0] = 'A';
name[5] = '\0'; // 将字符串截断为"Alice"
name[6] = 'A'; // 输出到 \0 后截断,后面的内容不会输出
// 再次输出修改后的字符串
printf("Modified name: %s\n", name); // Alice
// 动态读取用户输入并保存到字符数组中
char input[50];
printf("Enter your name: ");
scanf("%49s", input); // 注意限制输入长度防止溢出
printf("You entered: %s\n", input);
return 0;
}
示例
例 1:获取最大值和最小值
将用户输入的 10 个数字保存到数组,获取数组中的最大值和最小值。
int arr[10] = {}; // 初始化数组
int len = sizeof(arr) / sizeof(arr[0]); // 数组长度
printf("请输入 %d 个数字: \n", len);
for (int i = 0; i < len; i++)
{
scanf("%d", &arr[i]);
}
int max, min = 0;
for (int i = 0; i < len; i++)
{
if (i == 0)
{
max = arr[i];
min = arr[i];
}
else
{
if (arr[i] > max)
{
max = arr[i];
}
if (arr[i] < min)
{
min = arr[i];
}
}
}
printf("max: %d, min: %d\n", max, min);
例 2:反转数组
将用户输入的 10 个数字保存到数组,反转数组元素。
int arr[10] = {}; // 初始化数组
int len = sizeof(arr) / sizeof(arr[0]); // 数组长度
printf("请输入 %d 个数字: \n", len);
for (int i = 0; i < len; i++)
{
scanf("%d", &arr[i]);
}
// for (int i = 0; i < len / 2; i++)
for (int i = 0, j = len - 1; i < j; i++, j--)
{
int left = arr[i];
int right = arr[len - 1 - i];
// printf("i = %d, left = %d, right = %d\n", i, left, right);
arr[i] = right;
arr[len - 1 - i] = left;
}
for (int i = 0; i < len; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
例 3:保存输入到字符串
使用 scanf
读取输入到字符串时,遇到空格或回车会终止读取,看如下示例:
char s1[30] = {};
printf("输入字符串: \n");
scanf("%s", s1); // 输入 hello world
printf("输入的内容: %s", s1); // 输入的内容: hello
修改使用 fgets
函数可以解决这个问题:
char s1[30] = {};
printf("输入字符串: \n");
fgets(s1, sizeof(s1), stdin); // 输入 hello world
printf("输入的内容: %s", s1); // 输入的内容: hello world,会保存回车到 s1
s1[strlen(s1) - 1] = 0; // 消除获取到的回车
例 4:实现 strlen 的效果
方式一
char str[] = "hello world";
int len = sizeof(str) / sizeof(str[0]);
int result = 0;
for (int i = 0; i < len; i++)
{
if (str[i] == '\0')
{
break;
}
else
{
result++;
}
}
printf("result length: %d", result);
方式二
char str[30] = {};
printf("输入字符串: \n");
fgets(str, sizeof(str), stdin);
str[strlen(str) - 1] = 0;
int idx = 0;
while (str[idx] != '\0')
// while (str[idx])
{
idx++;
}
while (str[idx] != '\0' && ++idx);
printf("len: %d", idx);
例 5:字符串拷贝
char str1[30] = "";
char str2[30] = "";
printf("输入字符串: \n");
fgets(str1, sizeof(str1), stdin);
str1[strlen(str1) - 1] = 0;
int idx = 0;
while (str1[idx] != '\0')
{
str2[idx] = str1[idx];
idx++;
}
str2[idx] = '\0';
printf("str2: %s\n", str2);
例 6:字符串追加
方式一
char str1[128] = "hello";
char str2[128] = "world";
int str1Len = strlen(str1);
for (int i = 0; i < strlen(str2); i++)
{
str1[str1Len + i] = str2[i];
}
str1[str1Len + strlen(str2)] = '\0';
printf("str1: %s, len: %lu", str1, strlen(str1));
方式二
char str1[128] = "hello";
char str2[128] = "world";
int idx1 = 0, idx2 = 0;
// 找到 str1 结束索引的位置
while (str1[idx1] && ++idx1)
;
// 循环 str2
while (str2[idx2])
{
str1[idx1] = str2[idx2];
idx1++;
idx2++;
}
str1[idx1] = '\0';
printf("str1: %s len: %lu", str1, strlen(str1));
字符串中查找字符
char str[128] = "";
printf("请输入一个字符串: \n");
fgets(str, sizeof(str), stdin);
str[strlen(str) - 1] = '\0';
printf("请输入查找的字符: \n");
char c = getchar();
int idx = 0;
while (str[idx] != '\0')
{
if (str[idx] == c)
{
break;
}
idx++;
}
if (str[idx] == '\0')
{
printf("找不到\n");
return;
}
else
{
printf("找到了, 索引为: %d\n", idx);
}
插入字符串
char str1[128] = "";
char str2[128] = "";
int pos = 0;
printf("请输入第 1 个字符串: \n");
fgets(str1, sizeof(str1), stdin);
str1[strlen(str1) - 1] = '\0';
printf("请输入第 2 个字符串: \n");
fgets(str2, sizeof(str2), stdin);
str2[strlen(str2) - 1] = '\0';
printf("请输入要插入的位置索引: \n");
scanf("%d", &pos);
if (pos >= strlen(str1) || pos < 0)
{
printf("指定位置超出 str1 实际内容索引界限\n");
return;
}
// 让 str1 中间空出 str2 长度的位置
for (int i = strlen(str1) - 1; i >= pos; i--)
{
str1[strlen(str2) + i] = str1[i];
}
// 在 str1 中插入 str2
for (int i = 0; i < strlen(str2); i++)
{
str1[pos + i] = str2[i];
}
str1[strlen(str1) + strlen(str2)] = '\0';
printf("str1: %s, sizeof: %lu\n", str1, sizeof(str1));
评论区