C语言数组使用、数组相关的宏定义剖析,及矩阵乘积、杨辉三角实例

     数组一直是编程语言学习中需要重点掌握的部分,它是最基本的数据结构类型,是构成字符串及其他许多重要构造结构的基础。相对许多其他高级语言来说,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.二维数组的使用同一维数组完全类似,只不过每一个一维数组的元素又是一个数组而已;多维数组完全类似,只要细心处理,就不会出现错误。

矩阵计算C语言源码:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

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<stdio.h>
#include<stdlib.h>

#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");
    }
}

     上述代码的运行结果为:
        产生的13行杨辉三角

在宏定义中使用数组

     C语言中定义函数宏,实际上是在编译预处理时在被调用处将宏展开。通过宏定义的形式大大减少了工作量,而且有时候会使得程序运行时栈空间深度更浅,直接贴代码如下

#include<stdio.h>
#include<stdlib.h>

#define SHOW_ARRAY(array){\
            int lengthOfArray=sizeof(array)/sizeof(array[0]);\
            for(int i=0;i<lengthOfArray;i++){\
                printf("%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;i<lengthOfArray;i++){\
                printf("%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”:
       示例




注:

  1. 字符数组的定义 比较灵活且更加容易出错,后续专门整理.
  2. 在赋值前指定大小: 这种情况也是合法的,但是绝不可以超过定义的大小,见:错误示例代码中的错误形式:04.
  3. 左值/右值:在编程语言中处于赋值符号左右两边的变量值,要注意左值一般是要被赋值的。
  4. 这是C语言中唯一正确的不在定义时就赋值的数组定义方法!
  5. 也叫直接寻址或直接访问方式,在访问 a[k] 时计算机内部存储器中对PC指针进行了如下运算: pc = sizeof(type)*k + &(a[0])
  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值