嵌入式学习第二周(C语言数组)

C语言数组


        一、数组的分类

1.1按元素的类型分类


1)字符数组

      即若干个字符变量的集合,数组中的每个元素都是字符型的变量

      char s[10]; s[0],s[1]....s[9];

2)短整型的数组

      short int a[10]; a[0] ,a[9]; a[0]=4;a[9]=8;

3)整型的数组

      int a[10]; a[0] a[9]; a[0]=3;a[0]=6;

4) 长整型的数组

      lont int a[5];

5)浮点型的数组(单、双)

      float a[6]; a[4]=3.14f;

      double a[8]; a[7]=3.115926;

6)指针数组

      char *a[10]

      int *a[10];

7)结构体数组

      struct stu boy[10];

2.2 按维数分类


(1)一维数组

      int a[30];

      类似于一排平房

(2)二维数组

      int a[2][30];

      可以看成一栋楼房 有多层,每层有多个房间,也类似于数学中的矩阵

      二维数组可以看成由多个一维数组构成的。 有行,有列,

(3)多维数组

      int a[4][2][10];

      三维数组是由多个相同的二维数组构成的

      int a[5][4][2][10];


二、一维数组

1.1一维数组的创建和初始化
(1)数组的创建
  • 数组名字符合标识符的书写规定(数字、英文字母、下划线)

  • 数组是一组相同类型元素的集合

  • 数组名不能与其它变量名相同,同一作用域内是唯一的

  • 方括号[]中常量表达式表示数组元素的个数

  • 定义格式:类型 数组名[常量表达式];

//代码1
int arr1[10]; //根据定义的数据类型给数组的元素分配空间
char arr2[10];  //char 每个元素占用一个字节
float arr3[1];    
double arr4[20];
//代码2
//用宏定义的方式
#define X 3
int arr5[X];
//代码3
//错误使用
int count = 10;
int arr6[count];//数组时候可以正常创建?

:数组创建, [] 中要给一个常量才可以,不能使用变量。可以直接用常量,或者使用宏定义

(2).数组的初始化 

        在定义数组的同时进行赋值,称为初始化。全局数组若不初始化,编译器将其初始化为零。局部数组若不初始化,内容为随机值。 (全局作用域为0,局部作用域为随机数)

  1. 数组大小和数值个数一致
int arr1[5] = {1,2,3,4,5};//数组大小要与元素个数一致,不能超过数组大小

       2. 数组大小大于初始数

int arr2[6] = {1,2,3}; //后面的位置没有给值,默认给0

 

         3.不指定数组大小

int arr3[] = {1,2,3,4}; //系统根据元素的个数分配空间

        4.不指定字符数组大小

char arr5[] = {'a','b','c'}; //同样根据字符个数分配数组空间
         5.字符串数组(\0占用一个位置)

           (1)字符数组存储字符串

char arr6[] = "abcdef"; //字符串长度为7 \0占用一个字节

sizeof(arr6)/sizeof(char) //可以用这个计算字符的长度或者用函数

           (2)字符数组的大小和字符串字符个数一致时

char arr6[6] = "abcdef"; //会报错

 !!这样初始化是有问题的,因为无法正常读取字符串的结束标志('\0'),导致字符串的长度和内容不能得知!!

          (3)字符数组大小大于字符串中的字符数

 char arr7[6] = "zxc"; //剩余的初值给0

        (4)字符串的输入输出

     ①输入 (字符用getchar  字符串用gets)

  • scanf()函数:不能输入包含空格的句子。

       char str[20]; scanf(“%s”, str);    当输入How  are  you时,只能接收到How

  • gets()函数:能输入完整的句子,弥补了scanf函数不能输入包含空格的句子的不足。输入一行字符时,以Enter键作为结束符。在向字符数组赋值时,自动将’\n’转化为’\0’,作为字符串的结束标志。

用gets()函数可以输入空格,回车键结束并给数组存入’\0’结束  //推荐使用这种

 

     ②输出 (字符用putchar  字符串用puts)

printf()函数:依次输出字符串中的每个字符直到遇到字符串结束符’\0’。若printf()函数输出项的字符数组中不止一个’\0’,则输出时遇到第一个’\0’就结束。输出字符串后不会自动换行。 

char str[] = “China”; 
printf(“%s”, str); //%s字符串输出

 

 puts()函数:将一个字符串(以’\0’结束的字符序列)输出到终端。在输出时,将字符串的结束符’\0’自动转化为’\n’, 即输出完字符串之后自动换行。 推荐使用这种

 (3)补充

        (1)数组的数组名==数组首地址==第0个元素的地址

        (2) 通常针对数组进行操作时,最有效的途径是使用循环结构

        (3)数组的下标不能是小数,没有小数下标

结论

  1. 数组是具有相同类型的集合,数组的大小(即所占字节数)由元素个数乘以单个元素的大小。
  2. 数组只能够整体初始化,不能被整体赋值。只能使用循环从第一个逐个遍历赋值。
  3. 初始化时,数组的维度或元素个数可忽略 ,编译器会根据花括号中元素个数初始化数组元素的个数。
  4. 当花括号中用于初始化值的个数不足数组元素大小时,数组剩下的元素依次用0初始化。
  5. 字符型数组在计算机内部用的时对应的ascii码值进行存储的。
  6. 一般用”“引起的字符串,不用数组保存时,一般都被直接编译到字符常量区,并且不可被修改
  1.2 一维数组的使用

[ ] ,下标引用操作符。它其实就数组访问的操作符

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };//数组的不完全初始化
	   //计算数组的元素个数
	int sz = sizeof(arr) / sizeof(arr[0]);
	//对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
	int i = 0;//做下标,此时可以是变量
	for (i = 0; i < 10; i++)
	{
		arr[i] = i;
	}
	//输出数组的内容
	for (i = 0; i < 10; ++i)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

注意:

  • sizeof()操作符用于取长度,以字节为单位。sizeof(数组名)即求的时整个数组的大小。sizeof(首元素)即求数组单个元素大小。用0下标,是因为数组至少存在一个有效元素,所以0下标永远存在。
  • 数组是使用下标来访问的,下标是从0开始。
  • 数组的大小可以通过计算得到。建议采用sizeof(arr)/sizeof(arr[0])这种方式。

总结:

  1. 数组在内存中开辟是线性连续且递增的。
  2. 在c语言中,任何变量(基本变量,指针变量,结构体变量,数组变量)的空间都是整体开辟,但任何元素的起始地址一定是开辟字节当中最小的

 三、二维数组

     1.1 二维数组的创建和初始化

 (1)二维数组的创建

//数组创建
int arr[3][4];//[行数][列数]
char arr[][5];  //行可以没有,,但是列必须要给值
double arr[2][4];

二维数组创建时,行数可以忽略不写。并且所有维度的数组其第一个方括号的内容可忽略。

(2)二维数组的初始化

//数组初始化
int arr[3][4] = {1,2,3,4};
int arr[3][4] = {{1,2},{4,5}};
int arr[][4] = {{2,3},{4,5}};

注意:
        花括号中的一个花括号代表一个一维数组的初始化。当里面无花括号分组时,按照顺序从第一个开始逐个进行初始化。余下的未赋值的元素用0初始化。

     1.2 二维数组的使用

二维数组的使用也是通过下标的方式,用双重循环嵌套进行索引使用。

#include <stdio.h>
int main()
{
	int arr[3][4] = { 0 };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			arr[i][j] = i * 4 + j; //循环嵌套赋值
		}
	}
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}
	}
	return 0;
}
       1.3 二维数组在内存中的存储

  二维数组在内存中是按行的顺序存储的,即先存放第0行的各列数据,在存放第1行的,以此类推。

注意:

  1. 二维数组在内存的空间布局上,也是线性连续且递增的!!!
  2. 二维数组本质上也是一维数组,只不过内部元素放的是一维数组

 四、数组作为函数参数

  1. 调用函数传参数组时,减少函数传数组时的成本问题(时间和空间)。因为传参时,需要临时拷贝,如果数组过大,可能会浪费资源,严重的话可能栈溢出。
  2. 数组元素降维成指向数组内部元素类型指针
  3. 对指针加一,加上所指向的类型的大小。
1.1 一维数组
#include<stdio.h>

void Lisa(int arr[])
{
        printf("a = %d\n", sizeof(arr));//数组降维成指针后的指针大小,在32位系统下指针都为4字节
        printf("b = %d\n", sizeof(arr[0]));//数组首元素的大小
        printf("sz =a / b  = %d\n", sizeof(arr) / sizeof(arr[0]));//大小为1
        printf("arr = %p\n", arr);//数组首元素地址
        printf("&arr = %p\n", &arr);//指针的地址
        printf("arr + 1 = %p\n", arr + 1);//下一个元素的地址
        printf("&arr + 1 = %p\n", &arr + 1);//指针下一项的地址
}

int main(void)
{
        int Shuzu[10] = { 0,1,2,3,4,5,6,7,8,9 };
        printf("a = %d\n", sizeof(Shuzu));//数组总大小
        printf("b = %d\n", sizeof(Shuzu[0]));//数组首元素大小
        printf("sz =a / b = %d\n", sizeof(Shuzu) / sizeof(Shuzu[0]));//数组元素个数
        printf("Shuzu = %p\n", Shuzu);//数组首元素地址
        printf("&Shuzu = %p\n", &Shuzu);//代表整个数组,但是地址仍是首元素地址
        printf("Shuzu + 1 = %p\n", Shuzu + 1);//下一个元素的地址
        printf("&Shuzu + 1 = %p\n", &Shuzu + 1);//跳过整个数组后紧挨着的地址
                                                               //此时该地址减去首元素地址等于数组大小
        printf("\n\n");
        Lisa(Shuzu);

        return 0;
}

总结:

  1. 形参格式,例如int arr[ ]或者int *arr,两者等价
  2. 形参元素个数可被忽略,并且建议忽略(有可能改变了实参的大小,这样比较方便)。或者也可以填写比实参元素个数大的值。
  3. sizeof()求数组元素个数时,尽量在数组定义时求。因为传参后数组会降维成指针。

 1.2二维数组

      前面说了数组元素降维成指向数组内部元素类型指针,二维int整型数组的内部元素不再是int整型,而是具有四个整型的一维数组。
     对指针加一,加上所指向的类型的大小。对二维数组的指针加一,加上的值为内部一维数组的大小

#include<stdio.h>

void Lisa(int arr[][4])
{
        printf("a = %d\n", sizeof(arr));//数组降维成指针后的指针大小,在32位系统下指针都为4字节
        printf("b = %d\n", sizeof(arr[0][0]));//数组首元素的大小
        printf("sz =a / b  = %d\n", sizeof(arr) / sizeof(arr[0][0]));//大小为1
        printf("arr = %p\n", arr);//数组首元素地址
        printf("arr + 1 = %p\n", arr + 1);//下一个元素的地址
        printf("&arr = %p\n", &arr);//指针的地址
        printf("&arr + 1 = %p\n", &arr + 1);//指针下一项的地址
}

int main(void)
{
        int Shuzu[3][4] = { 0,1,2,3,4,5,6,7,8,9 };
        printf("a = %d\n", sizeof(Shuzu));//数组总大小
        printf("b = %d\n", sizeof(Shuzu[0][0]));//数组首元素大小
        printf("sz =a / b = %d\n", sizeof(Shuzu) / sizeof(Shuzu[0][0]));//数组元素个数
        printf("Shuzu = %p\n", Shuzu);//数组首元素地址
        printf("Shuzu + 1 = %p\n", Shuzu + 1);//下一个元素的地址,这时其内部元素的一维数组
        printf("&Shuzu = %p\n", &Shuzu);//代表整个数组,但是地址仍是首元素地址
        printf("&Shuzu + 1 = %p\n", &Shuzu + 1);//跳过整个数组后紧挨着的地址
                                                //此时该地址减去首元素地址等于数组大小
        printf("\n\n");
        Lisa(Shuzu);

        return 0;
}

  形参格式,例如:int arr[][4]或者int (*arr)[4],这里为指向具有四个整型元素的一维数组的数组指针。除了第一个中括号里的数字可以省,后面的中括号的内容不能省略,因为下标是数组类型的一部分,省略掉就不明确其类型


注意:
   看待所有的数组时,都将它看作一维数组,只不过其内部元素不一样,例如:三维数组其内部元素为二维数组,而二维数组也是有一维数组组成,都是线性连续且相等的。

数组指针和指针数组

  • 数组指针:是指针,指向数组。例:int (*arr)[10]
  • 指针数组:是数组,数组内容存放的是指针。例:int *arr[10]

然后,需要明确一个优先级顺序:() > [] > *
所以:
    (*p)[n]:根据优先级,先看括号内,则p是一个指针,这个指针指向一个一维数组,数组长度为n,这是“数组的指针”,即数组指针;
    *p[n]:根据优先级,先看[],则p是一个数组,再结合*,这个数组的元素是指针类型,共n个元素,这是“指针的数组”,即指针数组

1.指针数组

        用法:

#include<stdio.h>

int main(void)
{
        int *p[4];
        int arr1[3] = { 1,2,3 };
        int arr2[4] = { 2,4,6,8 };
        int arr3[5] = { 0 };
        int arr4[2] = { 2,2 };
        p[0] = arr1;
        p[1] = arr2;
        p[2] = arr3;
        p[3] = arr4;
        printf("%d\n", *(p[0] + 1));
        printf("%d\n", *(p[1] + 1));
        printf("%d\n", *(p[2] + 1));
        printf("%d\n", *(p[3] + 1));

        return 0;
}

 输出结果:2   4  0  2

首先,对于语句int*p[4],因为[ ]的优先级要比*要高,所以 p 先与[ ]结合,构成一个数组的定义,数组名为 p,而int*修饰的是数组的内容,即数组的每个元素。也就是说,该数组包含 4 个指向int类型数据的指针, 

  2.数组指针
#include<stdio.h>

int main(void)
{
        int Shuzu[3][4] = { 0,1,2,3,4,5,6,7,8,9,0,0 };
        int(*arr)[4] = Shuzu;
        for (int i = 0;i < 3;i++)
        {
               for (int j = 0;j < 4;j++)
               {
                       printf("arr[%d][%d]=%d  ", i,j,arr[i][j] );
               }
               printf("\n");
        }

        return 0;
}

 其次,对于语句int(*arr)[4],“( )”的优先级比[ ]高, *号和 arr 构成一个指针的定义,指针变量名为 arr,而 int 修饰的是数组的内容,即数组的每个元素。也就是说,arr 是一个指针,它指向一个包含 4 个int类型数据的数组,如图 所示。很显然,它是一个数组指针

输出:

 总结:

  • 数组的内容居多,用法也多,配合指针可以解决很多问题
  • 指针可访问的内存方式太深,后续再进行指针的学习

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值