[C语言] 04--数组

1.基本概念

逻辑: 一次性定义多个相同类型的变量,并且给他分配一片连续的内存
语法:int arr [5] ;
在这里插入图片描述

初始化:
只有在定义的时候赋值, 才可以称为初始化。数组只有在初始化的时候才可以统一赋值。

int arr [5]  = {1,2,3,4,5} ; // 定义并初始化数组
int arr [5]  = {1,2,3} ; //可以, 不完全初始化 
int arr [5]  = {1,2,3,4,5,6,7,8,9} ; // 错误(但是可以用) , 越界初始化, 越界部分将会被编译器舍弃
int arr [ ]  = {1,2,3,4,5,6,7,8,9} ; // 可以, 用户没有直接给定数组大小,

// 但是有初始化, 因此数组的大小会在初始化时确定, 大小为 9 
int arr [ ] ;  // 错误的, 没有给定大小也没有初始化, 因此数组的内存大小无法确定系统无法分配

在这里插入图片描述

注意:
数组在定义的时候必须确定他的大小。说白了就是中括号中[] 必须有数组的大小,如果没有就必须初始化。
数组元素引用:
存储模式:一片连续的内存,按照数据的类型进行分割成若干个大小相同的格子
元素的下标与偏移量:以数组开头为基础的偏移的量(数据类型大小)
在这里插入图片描述

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

printf("arr[0]:%d\n" , arr[0]);
arr[0] = 99 ;  //  把数组的第1个元素( 偏移量为0 )修改为 99  
printf("arr[0]:%d\n" , arr[0]);
arr[5] = 250 ;   //"错误" 越界访问, 并很有可能造成非法访问
printf("arr[5]:%d\n" , arr[5]);
arr = {9,8,7,6,5,4};  // 整体赋值只允许在初始化中
arr = 100 ;  // 错误 

printf("sizeof(arr):%ld\n" , sizeof(arr));
int len = sizeof(arr) / sizeof(int) ; //  求数组元素的个数
for (size_t i = 0; i < len ; i++)
{
     printf("arr[%ld]:%d\n" , i , arr[i]); 
}

2.字符数组

概念: 专门用来存放字符类型数据的数组, 称为字符数组
初始化+引用:

char ch1 [5] = {'H','e','l','l','o'} ; // 定义一个字符类型的数组并把'H','e','l','l','o' 一个一个存进去
char ch2 [6] = {"Hello"} ; // 定义一个字符型的数组, 并把 "Hello" 字符串存放到数组中 ,因此该数组为字符串数组

char ch3 [6] = "Hello" ;  // 与ch2 一样, 大括号可以省略
ch3[1] = 'E' ; // 可以, 把数组中第二个元素‘e’修改为‘E’
ch3 = "Even" ; //  不可以, 只有在初始化的时候才能整体赋值

printf("%s\n" , ch1); // 在访问ch1的时候并没有发现结束符,因此很有可能会把ch2的内容一并输出

注意:
ch1 为字符数组, 它没有结束符,因此在打印输出的时候应该避免使用 %s 进行输出, 有可能会 造成越界访问。
在这里插入图片描述

3.数组名的含义

表示整个数组的首地址
①在数组定义的时候
②在使用sizeof 运算符中 数组名表示整个数组的首地址(求得整个数组的大小)
③在取地址符 中 &arr , arr 表示整个数组
表示整个数组首元素的首地址
①其它情况

int arr[10] ;  // arr 表示整个数组的首地址
int len = sizeof arr ; // arr  表示整个数组的首地址  , sizeof 运算符后的括号可以省略
int (* p) [10] = &arr;  //arr 表示整个数组的首地址

int *p1 = arr ; //  arr 表示数组的首元素的首地址

字符串常量:
字符串常量是一个被存放在常量区的字符串,实际上也可称为一个匿名数组。
匿名数组,同样满足数组名的含义。

char  * msg2 = "Hello Even" ;// "Hello Even" 字符串常量首元素的首地址
char  * msg1 = "Hello Even"+1 ;

printf("%s\n", "Hello Even" ) ;// "Hello Even" 字符串常量首元素的首地址
printf("%s\n", &"Hello Even" ) ; // "Hello Even" 字符串常量的整个数组的地址


printf("%c\n", "Hello Even"[6] ) ; // "Hello Even" 字符串常量首元素的首地址 [6]
//[6]  相当于+6个单位(char) 得到 ‘E’

4.数组下标

//组的下标实际上只是编译器提供一种简写,实际上如下:
int a [100] ;
a[10] = 250 ;  ====>  *(a+10) = 250 ;

//  通过加法交换律,有如下结果:
a[10] = 250 ;
*(a+10) = 250 ;
*(10+a) = 250 ;
10[a] = 250 ;

5.零长数组

概念: 数组的长度为0 , char arr [0] ;
用途:一般会放在结构体的末尾, 作为可变长度的入口。(数组是唯一一个允许越界访问的载体)

struct node
{
    int a;
    char b;
    float c;
    ..
    ...
    int len;
    char arr[0];    
}

struct node *p = malloc(sizeof(struct node) + 20 );  // + 20 就是在原有的基础上增加20字节
p->len = 20 ; // 设置额外增长的长度为 20 
strncpy(p->arr , 20 , "Hello FZ2105");
p->arr

在这里插入图片描述

6.变长数组

概念: 定义是, 使用一个变量作为数组的长度(元素的个数)。
重点: 变长数组并不是说在任意时候他的长度可以随意变化, 实际上只是在定义之前数组的长度是未知的有一个变量来决定, 但是定义语句过后变长数组的长度由定义那一刻变量的大小来决定。

int a = 200 ; // a 作为一个普通的变量 ,  200 则可以作为arr 的长度
a = 99 ; // 99 可以作为 arr 的长度
int arr[a]; // a 当前是 99  , 因此数组arr 的长度已经确定为 99 
//从此以后该数组的长度已经确定为99 不会再变换
a = 10 ;  // a = 10 并不会影响数组的长度

注意:
①因为数组的长度未确定, 因此它不允许初始化。
②在使用的时候可以通过该变长数组来有限的节省内存空间。

7.多维数组

概念: 数组内部的成员也是数组

// 定义与初始化:
int arr[2][3] = { {1,2,3} , { 4,5,6} };
int arr1[2][3] = { 1,2,3,4,5,6};

//如何引用:
arr[0][0] = 100 ; // 数组:(通过下标来访问)
*(*(arr+0)+0) = 100 ; // 通过指针偏移来访问

实例:

int arr[2][3] = { {1,2,3} , { 4,5,6} };
int arr1[2][3] = { 1,2,3,4,5,6};
 
int *p = arr ; // p指向数组arr 的首元素
for (int i = 0; i < 2; i++)
{
     for (int j = 0; j < 3; j++)
     {
         printf("arr[%d][%d]:%d\t" ,i ,j , arr[i][j] );     
     }
}

printf("\n");

for (int i = 0; i < 6 ; i++)
{   //  *arr   得到元素1 的地址  + 1 则是加一个 int 类型       
  printf("*(*(arr+%d)):%d\t" , i,*(*(arr)+i) );

}

printf("\n");

for (int i = 0; i < 6 ; i++)
{      // arr  指的是首元素的首地址  {1,2,3} 的首地址  + 1则 + 3个整型
     printf("*(*(arr+%d)):%d\t" , i,*(*(arr+i)) );
}

printf("\n");

for (int i = 0; i < 6 ; i++)
{     // p 只是一个普通的整型指针, 与二维数组没有任何的关系
      printf("*(p+%d):%d\n" , i ,*(p+i));
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值