1.1数组概念
C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。
所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。
1.2 数组的特点
数组是一种数据结构,它由一组相同类型的元素组成。数组的特点包括:
-
随机访问:可以通过索引来快速访问数组中的任意元素,时间复杂度为O(1)。
-
连续存储:数组中的元素在内存中是连续存储的,因此可以通过指针算术运算来定位元素的位置。
-
固定长度:数组的长度在创建时就确定,并且不能动态改变。
-
类型一致:数组中的元素必须具有相同的数据类型。
-
内存占用:数组的内存占用是连续的,没有额外的空间开销。
-
插入和删除困难:由于数组的长度固定且元素连续存储,插入和删除元素可能需要移动其他元素,因此效率较低。
-
数组索引从0开始:在大多数编程语言中,数组的索引从0开始,即第一个元素的索引为0,第二个元素的索引为1,依此类推。
-
可以存储任意类型的数据:数组可以存储任意类型的数据,包括基本数据类型和自定义数据类型。
1.3 数组分类
C语言数组可以分为一维数组和多维数组两种类型。一维数组是一组相同类型的元素的集合,可以通过一个索引来访问每个元素。而多维数组是由多个一维数组组成的,可以通过多个索引来访问每个元素。
注!全局数组:若不初始化,编译器将其初始化为0
局部数组:若不初始化,内容为随机值。
下面是一维数组的代码示例:
注!!数组名不能与变量名相同.
#include <stdio.h>
int main() {
int nums[5]; // 定义一个包含5个整数的一维数组
// 给数组赋值
nums[0] = 10;
nums[1] = 20;
nums[2] = 30;
nums[3] = 40;
nums[4] = 50;
// 访问数组元素并打印
printf("nums[0] = %d\n", nums[0]);
printf("nums[1] = %d\n", nums[1]);
printf("nums[2] = %d\n", nums[2]);
printf("nums[3] = %d\n", nums[3]);
printf("nums[4] = %d\n", nums[4]);
return 0;
}
输出结果:
nums[0] = 10
nums[1] = 20
nums[2] = 30
nums[3] = 40
nums[4] = 50
下面是多维数组的代码示例:
#include <stdio.h>
int main() {
int matrix[2][3]; // 定义一个2行3列的二维数组
// 给数组赋值
matrix[0][0] = 1;
matrix[0][1] = 2;
matrix[0][2] = 3;
matrix[1][0] = 4;
matrix[1][1] = 5;
matrix[1][2] = 6;
// 访问数组元素并打印
printf("matrix[0][0] = %d\n", matrix[0][0]);
printf("matrix[0][1] = %d\n", matrix[0][1]);
printf("matrix[0][2] = %d\n", matrix[0][2]);
printf("matrix[1][0] = %d\n", matrix[1][0]);
printf("matrix[1][1] = %d\n", matrix[1][1]);
printf("matrix[1][2] = %d\n", matrix[1][2]);
return 0;
}
输出结果:
matrix[0][0] = 1
matrix[0][1] = 2
matrix[0][2] = 3
matrix[1][0] = 4
matrix[1][1] = 5
matrix[1][2] = 6
在C语言中,数组可以按元素类型分为以下几种分类:
注! 数组变量一旦生成,数组名指向的地址就不可更改。在声明时,编译器会自动给声明分配地址,与数组名绑定,不可更改。
- 整型数组:数组中的元素都是整数类型,包括int、short、long等。例如:
int numbers[5] = {1, 2, 3, 4, 5};
short temperatures[7] = {-5, 10, 15, 20, 25, 30, 35};
long scores[3] = {1000, 2000, 3000};
2. 浮点型数组:数组中的元素都是浮点数类型,包括float、double等。例如:
float prices[4] = {1.99, 2.49, 0.99, 1.89};
double measurements[6] = {10.5, 15.3, 20.0, 25.8, 30.4, 35.1};
3. 字符型数组:数组中的元素都是字符类型,包括char。例如:
char name[6] = {'J', 'o', 'h', 'n', ' ', 'D'};
char message[] = "Hello World";
4. 字符串数组:数组中的元素都是字符串类型,即以null字符'\0'结尾的字符数组。例如:
char names[3][10] = {"Alice", "Bob", "Charlie"};
5. 结构体数组:数组中的元素都是结构体类型。例如:
struct Point {
int x;
int y;
};
struct Point points[2] = {{1, 2}, {3, 4}};
6. 指针数组:数组中的元素都是指针类型。例如:
int* ptrs[3] = {&a, &b, &c};
1.4 长度大小
C语言数组的长度可以通过sizeof操作符获得。sizeof操作符是C语言中的一个关键字,用于查找数据类型占用的字节数。
下面是一个简单的代码示例,演示了如何使用sizeof操作符获取数组的长度字节大小。
#include <stdio.h>
int main() {
int arr[] = {1, 2, 3, 4, 5};
int length = sizeof(arr) / sizeof(arr[0]);
printf("数组长度为 %d\n", length);
printf("数组占用的字节大小为 %d\n", sizeof(arr));
return 0;
}
在上面的代码中,我们定义了一个整数类型的数组arr,并初始化了一些值。接下来,我们使用sizeof操作符计算了数组的长度,并将结果存储在变量length中。最后,我们打印了数组的长度和占用的字节大小。
运行上述代码,将得到以下输出:
数组长度为 5
数组占用的字节大小为 20
根据输出可知,数组arr的长度为5,占用的字节大小为20。这是因为arr中有5个元素,每个元素的字节大小为4(int类型),所以总共占用的字节大小为5 * 4 = 20。
注!!!sizeof返回值的数据类型为size_t,所以sizeof(a)/sizeof(a[0])的数据类型也是size_t,在pritnf()的占位符为%zu或%zd,%lld也行。
1.5 数组遍历
C语言数组遍历是指按照一定顺序,依次访问数组中的每个元素。一般来说,可以使用循环结构来实现数组遍历,常用的循环结构有for循环和while循环。
- 使用for循环遍历数组
#include <stdio.h>
int main() {
int arr[] = {1, 2, 3, 4, 5};
int length = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < length; i++) {
printf("%d ", arr[i]);
}
return 0;
}
2.使用while循环遍历数组
#include <stdio.h>
int main() {
int arr[] = {1, 2, 3, 4, 5};
int length = sizeof(arr) / sizeof(arr[0]);
int i = 0;
while (i < length) {
printf("%d ", arr[i]);
i++;
}
return 0;
}
1.6 变长数组
C语言中的可变长度数组是指数组的长度可以在运行时确定,并且可以动态地改变其长度。在C语言中,使用动态内存分配的方式来实现可变长度数组。
具体实现可变长度数组的方法有malloc,calloc或realloc动态分布和重新分配内存。即 允许运行时改变内存块的大小。
- 使用malloc函数动态分配内存:
int n;
scanf("%d", &n);
int* arr = (int*)malloc(n * sizeof(int));
if (arr == NULL) {
printf("内存分配失败!\n");
exit(1);
}
// 使用数组arr
// ...
free(arr); // 释放内存
2. 使用realloc函数重新分配内存:
int n;
scanf("%d", &n);
int* arr = (int*)malloc(n * sizeof(int));
if (arr == NULL) {
printf("内存分配失败!\n");
exit(1);
}
// 使用数组arr
// ...
int newSize;
scanf("%d", &newSize);
arr = (int*)realloc(arr, newSize * sizeof(int));
if (arr == NULL) {
printf("内存分配失败!\n");
exit(1);
}
// 使用重新分配后的数组arr
// ...
free(arr); // 释放内存
需要注意的是,在使用完可变长度数组后,需要使用free函数来释放动态分配的内存,以防止内 存 泄漏。
3. C99标准中还引入了可变长度数组的语法,可以直接在函数参数中使用可变长度数组,例如:
void printArray(int n, int arr[n]) {
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int n;
scanf("%d", &n);
int arr[n];
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
printArray(n, arr);
return 0;
}
以上就是C语言中实现可变长度数组的方法。
1.7 数组的复制
C语言中可以通过循环遍历数组元素并逐个复制到另一个数组中来实现数组的复制。具体的代码如下所示:
#include <stdio.h>
#define SIZE 5 // 数组大小
int main() {
int arr1[SIZE] = {1, 2, 3, 4, 5};
int arr2[SIZE];
// 复制数组
for (int i = 0; i < SIZE; i++) {
arr2[i] = arr1[i];
}
// 输出复制后的数组
printf("复制后的数组:");
for (int i = 0; i < SIZE; i++) {
printf("%d ", arr2[i]);
}
return 0;
}
#include <stdio.h>
#include <string.h>
int main() {
int source[] = {1, 2, 3, 4, 5};
int destination[5];
memcpy(destination, source, sizeof(source));
printf("源数组:");
for (int i = 0; i < sizeof(source)/sizeof(int); i++) {
printf("%d ", source[i]);
}
printf("\n");
printf("目标数组:");
for (int i = 0; i < sizeof(destination)/sizeof(int); i++) {
printf("%d ", destination[i]);
}
printf("\n");
return 0;
}
循环复制:简单直观,容易理解实现。需要循环遍历来逐个赋值。
memcpy函数复制:快速高效的内存复制适用于大型数组或复杂的数据结构,可以直接复制字节数,不用遍历。包含头文件<string.h>。
运行上述代码,将输出复制后的数组:1 2 3 4 5。可以看到,arr2数组成功地复制了arr1数组的值。
注!!!这种方法只适用于一维数组的复制。如果要复制的是二维数组或更高维的数组,则需要使用嵌套循环进行复制。
1.8 数组反转(倒序)
通过循环和临时变量实现:
方法一:
#include<stdio.h>
#define LENGTH 9
int main(){
int a[LENGTH]={10,20,30,40,50,60,70,80,90};
for(int i=0;i<LENGTH/2;i++){
int temp=a[i];
a[i]=a[LENGTH-1-i];
a[LENGTH-1-i]=temp;
}
for(int i=0;i<LENGTH;i++){
printf("%d ",a[i];
}
printf("\n");
return 0;
}
方法二:
#include<stdio.h>
#define LENGTH 9
int main(){
int a[LENGTH]={10,20,30,40,50,60,70,80,90};
int i=0;
int j=length-1;
int temp;
while(i<j){
temp=a[i];
a[i]=a[j];
a[j]=temp;
i++;
j--;
}
for(i=0;i<length;i++){
printf("%d,",a[i]);
}
return 0;
}
1.9 char型数组和字符串
字符数组和字符串的区别:
C语言中没有字符串这种数据类型,可以用char的数组来代替
以数字0(和字符‘\0’等价)结尾的char数组就是字符串---是特殊的char数组
注!!如果char数组没有以字符0结尾,那么就不是一个字符串,只是普通字符数组。
格式:char str[ ]={'h','e','r','t','\0'}; //其中\0也会占一个位置。
简化写法:
char str1[12]={"hello world"}; 或者 char str1[12]="hello world"; 双引号的字符,会自动视为字符数组。字符数组的长度可以由编译器自动计算,所以声明时可以省略长度。
str1和str2的输出为'h','e','l','l','o',' ','w','o','r','l','d','\0'
数组由连续的存储单元组成,每个单元存储一个字符,长度不是11,是12 。
char a[10]={"China"};第六个元素为\0,后四位也是。
字符 \0 Ascll码为0,‘0‘Ascll码为48.