第一项 C 数组
可以存储一个固定大小的相同类型元素的顺序集合。用来存储一系列数据,被认为是一系列相同类型的变量。
先声明一个数组变量,比如 runoob,然后使用 runoob[0]、runoob[1]、...、runoob[99] 来代表一个个单独的变量。
由连续的内存位置组成,最低地址对应第一个元素,最高地址对应最后一个元素。
特定元素可通过索引访问,第一个索引值为 0。
C 语言可使用指针来处理数组。
声明数组
指定元素的类型和元素的数量
一维数组:
type arrayName [ arraySize ];
arraySize 是一个大于零的整数常量,type 可是任意有效的 C 数据类型。
初始化数组
可以逐个初始化数组,可以使用初始化语句
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
{ } 值的数目不能大于在数组声明时在 [ ] 中指定的元素数目。
省略掉数组的大小,数组大小则为初始化时元素的个数。
double balance[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
为数组中某个元素赋值:
balance[4] = 50.0;
所有数组都是以 0 作为它们第一个元素的索引,也被称为基索引,数组的最后一个索引是数组的总大小减去 1。
访问数组元素
可通过数组名称加索引进行访问。元素索引是放在方括号内,跟在数组名称的后边。
double salary = balance[9];
eg:
#include <stdio.h>
int main ()
{
int n[ 10 ]; /* n 是一个包含 10 个整数的数组 */
int i,j;
/* 初始化数组元素 */
for ( i = 0; i < 10; i++ )
{
n[ i ] = i + 100; /* 设置元素 i 为 i + 100 */
}
/* 输出数组中每个元素的值 */
for (j = 0; j < 10; j++ )
{
printf("Element[%d] = %d\n", j, n[j] );
}
return 0;
}
Element[0] = 100 Element[1] = 101 Element[2] = 102 Element[3] = 103 Element[4] = 104 Element[5] = 105 Element[6] = 106 Element[7] = 107 Element[8] = 108 Element[9] = 109
获取数组长度
可使用 sizeof 运算符来获取数组的长度
int numbers[] = {1, 2, 3, 4, 5}; int length = sizeof(numbers) / sizeof(numbers[0]);
eg:
#include <stdio.h>
int main() {
int array[] = {1, 2, 3, 4, 5};
int length = sizeof(array) / sizeof(array[0]);
printf("数组长度为: %d\n", length);
return 0;
}
eg (使用宏定义):
#include <stdio.h>
#define LENGTH(array) (sizeof(array) / sizeof(array[0]))
int main() {
int array[] = {1, 2, 3, 4, 5};
int length = LENGTH(array);
printf("数组长度为: %d\n", length);
return 0;
}
数组长度为: 5
数组名
数组名表示数组的地址,即数组首元素地址。
int myArray[5] = {10, 20, 30, 40, 50};
myArray 数组名,表示整数类型数组,包含 5 个元素。myArray 也代表着数组的地址,即第一个元素的地址。
数组名本身是常量指针,值不能被改变。
使用&运算符来获取数组地址
int myArray[5] = {10, 20, 30, 40, 50}; int *ptr = &myArray[0]; // 或者直接写作 int *ptr = myArray;
ptr 指针变量被初始化为 myArray 的地址。
数组名会自动转换为指向数组首元素的指针。可直接将数组名用于指针运算:
eg:
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]); // 数组名arr被当作指针使用
}
}
int main() {
int myArray[5] = {10, 20, 30, 40, 50};
printArray(myArray, 5); // 将数组名传递给函数
return 0;
}
printArray 函数接受一个整数数组和数组大小作为参数,将 myArray 数组名传递给函数后,函数内部可以像使用指针一样使用 arr 数组名。
数组详解
概念 | 描述 |
---|---|
多维数组 | 最简单形式是二维数组。 |
传递数组给函数 | 可通过指定不带索引的数组名称来给函数传递一个指向数组的指针。 |
从函数返回数组 | 允许从函数返回数组。 |
指向数组的指针 | 可通过指定不带索引的数组名称来生成一个指向数组中第一个元素的指针。 |
静态数组与动态数组 | 静态数组在编译时分配内存,大小固定;动态数组在运行时手动分配内存,大小可变。 静态数组的生命周期与作用域相关,而动态数组的生命周期由程序员控制。 |
C 多维数组
多维数组声明一般形式:
type name[size1][size2]...[sizeN];
二维数组
本质上是一个一维数组的列表;声明一个 x 行 y 列的二维整型数组:
type arrayName [ x ][ y ];
type 可以是任意有效 C 数据类型,arrayName 是一个有效的 C 标识符。一个二维数组可以被认为是一个带有 x 行和 y 列的表格。下面是一个二维数组,包含 3 行和 4 列:
int x[3][4];
因此,数组中的每个元素是使用形式为 a[ i , j ] 的元素名称来标识的,其中 a 是数组名称,i 和 j 是唯一标识 a 中每个元素的下标。
初始化二维数组
多维数组可以通过在括号内为每行指定值来进行初始化。
int a[3][4] = { {0, 1, 2, 3} , /* 初始化索引号为 0 的行 */ {4, 5, 6, 7} , /* 初始化索引号为 1 的行 */ {8, 9, 10, 11} /* 初始化索引号为 2 的行 */ };
内部嵌套括号是可选的,下面的初始化与上面是等同的:
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
访问二维数组元素
二维数组中的元素是通过使用下标(数组的行索引和列索引)来访问的。例如:
int val = a[2][3];
用嵌套循环来处理二维数组:
eg:
#include <stdio.h>
int main ()
{
/* 一个带有 5 行 2 列的数组 */
int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}};
int i, j;
/* 输出数组中每个元素的值 */
for ( i = 0; i < 5; i++ )
{
for ( j = 0; j < 2; j++ )
{
printf("a[%d][%d] = %d\n", i,j, a[i][j] );
}
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
a[0][0] = 0 a[0][1] = 0 a[1][0] = 1 a[1][1] = 2 a[2][0] = 2 a[2][1] = 4 a[3][0] = 3 a[3][1] = 6 a[4][0] = 4 a[4][1] = 8
C 传递数组给函数
在函数中传递一个一维数组作为参数,须以下面三种方式来声明函数形式参数(结果一样),因为每种方式都会告诉编译器将要接收一个整型指针。同样地,您也可以传递一个多维数组作为形式参数。
方式 1
形式参数是一个指针:
void myFunction(int *param) { . . . }
方式 2
形式参数是一个已定义大小数组:
void myFunction(int param[10]) { . . . }
方式 3
形式参数是一个未定义大小数组:
void myFunction(int param[]) { . . . }
eg:
double getAverage(int arr[], int size)
{
int i;
double avg;
double sum;
for (i = 0; i < size; ++i)
{
sum += arr[i];
}
avg = sum / size;
return avg;
}
#include <stdio.h>
/* 函数声明 */
double getAverage(int arr[], int size);
int main ()
{
/* 带有 5 个元素的整型数组 */
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
/* 传递一个指向数组的指针作为参数 */
avg = getAverage( balance, 5 ) ;
/* 输出返回值 */
printf( "平均值是: %f ", avg );
return 0;
}
double getAverage(int arr[], int size)
{
int i;
double avg;
double sum=0;
for (i = 0; i < size; ++i)
{
sum += arr[i];
}
avg = sum / size;
return avg;
}
C 从函数返回数组
可以通过指定不带索引的数组名来返回一个指向数组的指针。
从函数返回一个一维数组,须声明一个返回指针的函数:
int * myFunction() { . . . }
在函数外返回局部变量的地址,须定义局部变量为 static 变量。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* 要生成和返回随机数的函数 */
int * getRandom( )
{
static int r[10];
int i;
/* 设置种子 */
srand( (unsigned)time( NULL ) );
for ( i = 0; i < 10; ++i)
{
r[i] = rand();
printf( "r[%d] = %d\n", i, r[i]);
}
return r;
}
/* 要调用上面定义函数的主函数 */
int main ()
{
/* 一个指向整数的指针 */
int *p;
int i;
p = getRandom();
for ( i = 0; i < 10; i++ )
{
printf( "*(p + %d) : %d\n", i, *(p + i));
}
return 0;
}
r[0] = 25307
r[1] = 10524
r[2] = 12795
r[3] = 8551
r[4] = 7738
r[5] = 19181
r[6] = 3581
r[7] = 4420
r[8] = 27202
r[9] = 7742
*(p + 0) : 25307
*(p + 1) : 10524
*(p + 2) : 12795
*(p + 3) : 8551
*(p + 4) : 7738
*(p + 5) : 19181
*(p + 6) : 3581
*(p + 7) : 4420
*(p + 8) : 27202
*(p + 9) : 7742
C 指向数组的指针
double balance[50];
balance 是一个指向 &balance[0] 的指针,数组 balance 的第一个元素的地址。
把 p 赋值为 balance 的第一个元素的地址:
double *p;
double balance[10];
p = balance;
使用数组名作为常量指针是合法的,反之亦然。
*(balance + 4) 是一种访问 balance[4] 数据的合法方式。
把第一个元素的地址存储在 p 中,可以使用 *p、*(p+1)、*(p+2) 等来访问数组元素。
#include <stdio.h>
int main ()
{
/* 带有 5 个元素的整型数组 */
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
int i;
p = balance;
/* 输出数组中每个元素的值 */
printf( "使用指针的数组值\n");
for ( i = 0; i < 5; i++ )
{
printf("*(p + %d) : %f\n", i, *(p + i) );
}
printf( "使用 balance 作为地址的数组值\n");
for ( i = 0; i < 5; i++ )
{
printf("*(balance + %d) : %f\n", i, *(balance + i) );
}
return 0;
}
使用指针的数组值
*(p + 0) : 1000.000000
*(p + 1) : 2.000000
*(p + 2) : 3.400000
*(p + 3) : 17.000000
*(p + 4) : 50.000000
使用 balance 作为地址的数组值
*(balance + 0) : 1000.000000
*(balance + 1) : 2.000000
*(balance + 2) : 3.400000
*(balance + 3) : 17.000000
*(balance + 4) : 50.000000
p 是一个指向 double 型的指针,可以存储一个 double 类型的变量。有 p 中的地址,*p 将给出存储在 p 中相应地址的值。
C 语言静态数组与动态数组
静态数组
是在编译时声明并分配内存空间的数组;具有固定的大小,声明数组时需指定数组长度。
int staticArray[5]; // 静态数组声明 int staticArray[] = {1, 2, 3, 4, 5}; // 静态数组声明并初始化
int array[] = {1, 2, 3, 4, 5}; int length = sizeof(array) / sizeof(array[0]);
sizeof(array) 返回整个数组所占用的字节数, sizeof(array[0]) 返回数组中单个元素的字节数,两者相除,得到了数组的长度。
eg:
#include <stdio.h>
int main() {
int staticArray[] = {1, 2, 3, 4, 5}; // 静态数组声明并初始化
int length = sizeof(staticArray) / sizeof(staticArray[0]);
printf("静态数组: ");
for (int i = 0; i < length; i++) {
printf("%d ", staticArray[i]);
}
printf("\n");
return 0;
}
静态数组: 1 2 3 4 5
动态数组
- 内存分配:动态数组的内存空间在运行时通过动态内存分配函数手动分配,并存储在堆上。需要使用
malloc
、calloc
等函数来申请内存,并使用free
函数来释放内存。 - 大小可变:动态数组的大小在运行时可以根据需要进行调整。可以使用
realloc
函数来重新分配内存,并改变数组的大小。 - 生命周期:动态数组的生命周期由程序员控制。需要在使用完数组后手动释放内存,以避免内存泄漏。
int size = 5; int *dynamicArray = (int *)malloc(size * sizeof(int)); // 动态数组内存分配 // 使用动态数组 free(dynamicArray); // 动态数组内存释放
int size = 5; // 数组长度 int *array = malloc(size * sizeof(int)); // 使用数组 free(array); // 释放内存
使用 malloc 函数动态分配了一个整型数组,将长度保存在变量 size 中;可以根据需要使用这个长度进行操作,在使用完数组后,使用 free 函数释放内存。
注意:动态数组的使用需要注意内存管理的问题,确保在不再需要使用数组时释放内存,避免内存泄漏和访问无效的内存位置。
eg:
#include <stdio.h>
#include <stdlib.h>
int main() {
int size = 5;
int *dynamicArray = (int *)malloc(size * sizeof(int)); // 动态数组内存分配
if (dynamicArray == NULL) {
printf("Memory allocation failed.\n");
return 1;
}
printf("Enter %d elements: ", size);
for (int i = 0; i < size; i++) {
scanf("%d", &dynamicArray[i]);
}
printf("Dynamic Array: ");
for (int i = 0; i < size; i++) {
printf("%d ", dynamicArray[i]);
}
printf("\n");
free(dynamicArray); // 动态数组内存释放
return 0;
}
声明了一个变量 size 来指定动态数组的大小;
使用 malloc 函数为动态数组分配内存,通过 sizeof 运算符计算所需的内存大小。
通过循环和 scanf 函数,从用户输入中读取元素值并存储到动态数组中。
第二项 C enum(枚举)
用于定义一组具有离散值的常量。
枚举类型为程序中的一组相关的常量取名字。
定义一个枚举类型,需使用 enum 关键字,后面跟着枚举类型的名称用 {} 括起来的一组枚举常量。每个枚举常量可以用一个标识符来表示,可以为它们指定一个整数值,如果没有指定,那么默认从 0 开始递增。
enum 枚举名 {枚举元素1,枚举元素2,……};
#define
#define MON 1
#define TUE 2
#define WED 3
#define THU 4
#define FRI 5
#define SAT 6
#define SUN 7
枚举:
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };
第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。
可以在定义枚举类型时改变枚举元素的值:
enum season {spring, summer=3, autumn, winter};没有指定值的枚举元素,其值为前一元素加 1。也就说 spring 的值为 0,summer 的值为 3,autumn 的值为 4,winter 的值为 5
枚举变量的定义
1、先定义枚举类型,再定义枚举变量
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN }; enum DAY day;
2、定义枚举类型的同时定义枚举变量
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } day;
3、省略枚举名称,直接定义枚举变量
enum { MON=1, TUE, WED, THU, FRI, SAT, SUN } day;
eg:
#include <stdio.h>
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
int main()
{
enum DAY day;
day = WED;
printf("%d",day);
return 0;
}
3
枚举类型是当做 int 或 unsigned int 类型处理。(一般来说无法遍历)
特殊的情况下,枚举类型必须连续是可以实现有条件的遍历。
使用 for 来遍历枚举的元素:
eg:
#include <stdio.h>
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
int main()
{
enum DAY day;
day = WED;
printf("%d",day);
return 0;
}
以上实例输出结果为:
枚举元素:1 枚举元素:2 枚举元素:3 枚举元素:4 枚举元素:5 枚举元素:6 枚举元素:7
以下枚举类型不连续,这种枚举无法遍历。
enum
{
ENUM_0,
ENUM_10 = 10,
ENUM_11
};
枚举在 switch 中的使用:
eg:
#include <stdio.h>
#include <stdlib.h>
int main()
{
enum color { red=1, green, blue };
enum color favorite_color;
/* 用户输入数字来选择颜色 */
printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): ");
scanf("%u", &favorite_color);
/* 输出结果 */
switch (favorite_color)
{
case red:
printf("你喜欢的颜色是红色");
break;
case green:
printf("你喜欢的颜色是绿色");
break;
case blue:
printf("你喜欢的颜色是蓝色");
break;
default:
printf("你没有选择你喜欢的颜色");
}
return 0;
}
请输入你喜欢的颜色: (1. red, 2. green, 3. blue): 1 你喜欢的颜色是红色
将整数转换为枚举
eg:
#include <stdio.h>
#include <stdlib.h>
int main()
{
enum day
{
saturday,
sunday,
monday,
tuesday,
wednesday,
thursday,
friday
} workday;
int a = 1;
enum day weekend;
weekend = ( enum day ) a; //类型转换
//weekend = a; //错误
printf("weekend:%d",weekend);
return 0;
}
weekend:1