数组一直是编程语言学习中需要重点掌握的部分,它是最基本的数据结构类型,是构成字符串及其他许多重要构造结构的基础。相对许多其他高级语言来说,C语言对数组本身提供的支持并不太多,尤其是不支持动态的数组定义。
本文总结了几种常见的数组使用中的错误用法,并通过分析原理解释错误原因,从而为掌握正确的数组用法提供帮助。同时提供了几个相对有代表性的数组的使用方式及源码,以方便学习。
在C语言中,数组按如下的方法定义:
① 类型 数组名[数组大小];
int array[10];
char str[15];
② 类型 数组名[]={元素1,元素2,元素3,...};1
int a={1,2,3,4,5};
char ch[]={'a','b','c'};
③ 类型 数组名[数组大小]={元素1,元素2,元素3,...};2
float x[4]={1.5, 3.2, 6.0, 23};
int y[5]={1,2,3,4};
/*
在下述代码代码片段中展示了几种常见的错误
*/
#define N 5
int main(){
/*错误形式 01: 声明数组时没有确定长度 */
int array1[];
/*错误形式 02:数组长度必须在进行编译初期就能确定,
而不能是在运算处理中才能计算出来的结果,如宏定义 */
int m=5;
int array[m];
/*错误形式 03: 先声明了数组,再赋值*/
int array2[N];
array2={1,2,3,4,5};
/*错误形式 04: 赋值范围超出了开辟的空间*/
int array3[N]={1,2,3,4,5,6};
/*错误形式 05: 试图进行对数组的整体赋值*/
int a[N]={1,2,3,4,5},b[N];
b=a;
return 0;
}
1. 数组在定义的时候,在内存空间中为其开辟了一块连续的空间,其大小为单个数组元素类型所占大小 sizeof(type) 与元素个数N的积,即:
size = sizeof(type) * N
2. 同一数组内的数据元素必须一样,即即便如下述定义:
float x[]={1, 2, 3, 4.0, 3, 44, 27, 8};
其结果也是使得所有的元素都被强制转换为float类型!
3. 数组一旦定义之后,数组名就表示数组的第一个元素的地址,很大程度上等同于指向该数组的指针,即:
x==&(x[0]);
//以下是关于该向量名称经常等同于指针来使用的情况的说明
float *p;
p = x; //或者 p = (float*)malloc(4)
memset(x, 10, 4); //将 x[0]到 x[3] 共4个位置赋值为10
memset(p, 10, 4); //将 float类型的地址从p开始到相邻的共4个位置全部赋值为10,和上一句效果相同
memset(x+2, 10, 4); //将 x[2]到 x[5] 共4个位置赋值为10
//数组名和指针,在以下表达式中不一样:
sizeof(x) //等于数组元素的个数,即8 ,其中x的定义是 float x[]={1, 2, 3, 4.0, 3, 44, 27, 8};
sizeof(p) //等于p的类型(float类型的指针)所占空间字节数,为4;
//题外话:
// 在32位系统中,所有类型的指针变量都存放的是该指针在内存中的地址,所以所占用的都是4个字节; 而64位系统中,则是8个字节!
如果试图按照这样的方式进行赋值:
int x[]={1,2,3,4,5,6},y[6];
y=x;
就会报错,因为这一句话相当于:
&(y[0])=&(x[0]);
错误原因在于,左边的表达式 &(y[0]) 是一个内存中既定的地址而非一个变量符号,它不可被用于左值!3故是一种错误。
4.正是由于上述原因,因此如果按以下方式进行数组的声明4:
int x[5];
//或者:
#define N 5
int x[N];
则必须对元素分别进行赋值,且只能通过下标的方式进行5,如:
int a[5];
{
a[i]=i;
}
//当所有元素赋值都相同时,也可以用 memset(a, 100, 5)的方式,比较简便
5.数组在进行函数调用时,传递给形参的值为该数组的名称 / 第一个元素的地址,因此不是值传递,在被调用函数中对数组的处理,都会导致原数组的值被改变,这一点尤其需要注意。如:
f(int x[]) // 定义函数f()
{
x[2] = -1;
}
int array[10] = {0};
f(array); // 调用 f()处理该向量
array[2] = ? // 结果是 -1, 这就是地址传递调用函数时产生的所谓的 “副作用”
// 你肯定接触过的另一个例子是:
// 排序函数,比如 sort(array),经过sort()排序函数处理后,array向量中的各个元素被改写了
6.数组在进行函数调用时,传递给形参的值为该数组的第一个元素的地址,在进行处理时计算机不知道该连续的数组地址到哪里结束,因此必须同时再传入一个指定的大小参数:length,见上例。
7.二维数组的使用同一维数组完全类似,只不过每一个一维数组的元素又是一个数组而已;多维数组完全类似,只要细心处理,就不会出现错误。
#include
#include
#include
void showYanghui(int );
#ifndef MM
#define MM 5
#endif
#ifndef NN
#define NN 5
#endif
#ifndef KK
#define KK 7
#endif
int main() {
srand((unsigned)time(NULL));
int a[MM][NN], b[NN][KK],C[MM][KK];
for (int i = 0; i < MM; i++) {
for (int j = 0; j < NN;j++) {
a[i][j] = (int)((rand()-RAND_MAX/2)%9);
}
}
for (int i = 0; i < NN; i++) {
for (int j = 0; j < KK; j++) {
b[i][j] = (int)((rand() - RAND_MAX / 2) % 9);
}
}
/*显示a,b矩阵*/
printf("matrix A=\n\n");
for (int i = 0; i < MM; i++) {
for (int j = 0; j < NN; j++) {
printf("%3d\t",a[i][j]);
}
printf("\n");
}
printf("\n"); printf("\n");
printf("matirx B=\n\n");
for (int i = 0; i < NN; i++) {
for (int j = 0; j < KK; j++) {
printf("%3d\t", b[i][j]);
}
printf("\n");
}
/*矩阵求积*/
for (int i = 0; i < MM; i++) {
for (int j = 0; j < KK; j++) {
int sum = 0;
for (int k = 0; k < NN; k++) {
sum += a[i][k] * b[k][j];
}
C[i][j] = sum;
}
}printf("\n"); printf("\n");
printf("C=A*B=\n\n");
for (int i = 0; i < MM; i++) {
for (int j = 0; j < KK; j++) {
printf("%3d\t",C[i][j]);
}
printf("\n");
}
getchar();
}
8.杨辉三角的完整实现:
#include
#include
#define N 20
void showYanghui(int );
int main() {
showYanghui(13);
return 0;
}
/*打印杨辉三角*/
void showYanghui(int n) {
/*产生杨辉三角的存储矩阵*/
int x[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (j == 0 || i == j) {
x[i][j] = 1;
}else {
x[i][j] = x[i - 1][j - 1] + x[i - 1][j];
}
}
}
/*按照杨辉三角的显示形式显示*/
for (int i = 0; i < n; i++) {
for (int k = 0; k <( n-(i+1)); k++) {
printf(" ");
}
for (int j = 0; j <= i; j++) {
if (x[i][j] < 10) {
printf("%4d", x[i][j]);
}else if (x[i][j] < 100) {
printf("%4d", x[i][j]);
}else {
printf("%4d", x[i][j]);
}
}
printf("\n");
}
}
C语言中定义函数宏,实际上是在编译预处理时在被调用处将宏展开。通过宏定义的形式大大减少了工作量,而且有时候会使得程序运行时栈空间深度更浅,直接贴代码如下
#include
#include
#define SHOW_ARRAY(array){\
int lengthOfArray=sizeof(array)/sizeof(array[0]);\
for(int i=0;iprintf("%d\t",array[i]);\
if((i+1)%5==0){\
printf("\n");\
}\
}\
printf("\n");\
}
#define DISPLAY_ARRAY(str,array){\
int lengthOfArray=sizeof(array)/sizeof(array[0]);\
for(int i=0;iprintf("%s[%2d]=%d\t",str,i,array[i]);\
if(i!=0&&(i+1)%4==0){\
printf("\n");\
}\
}\
printf("\n");\
}
int main() {
int vectory[] = { 53,78,35,89,23,62,22,12,62,95,27,28,8,86,32 };
DISPLAY_ARRAY("vectory",vectory);
printf("\n");
SHOW_ARRAY(vectory);
return 0;
}
上述代码的运行结果为:
其中,自定义字段“vectory”是可以随意替换的,例如换成“arr”: