那些年你还没学会的C语言数组小细节(和bug郭一起学C系列)

举报
bug郭 发表于 2022/07/31 12:51:34 2022/07/31
【摘要】 失踪人口回归!互访,互粉,互相支持,谢谢大佬的指点!@TOC 本章重点一维数组的创建和初始化一维数组的使用一维数组在内存中的存储二维数组的创建和初始化二维数组的使用二维数组在内存中的存储数组作为函数参数 一维数组什么是数组呢?我们之前学过数组是一组数据,方便记录数据,那到底什么才是数组呢,今天我们就来详细介绍一下!数组的定义数组是一组相同类型元素的集合。相同类型元素的集合我们回忆一下学过那些...

失踪人口回归!互访,互粉,互相支持,谢谢大佬的指点!
在这里插入图片描述

@TOC

本章重点

  1. 一维数组的创建和初始化
  2. 一维数组的使用
  3. 一维数组在内存中的存储
  4. 二维数组的创建和初始化
  5. 二维数组的使用
  6. 二维数组在内存中的存储
  7. 数组作为函数参数

一维数组

什么是数组呢?
我们之前学过数组是一组数据,方便记录数据,那到底什么才是数组呢,今天我们就来详细介绍一下!
数组的定义

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

相同类型元素的集合
我们回忆一下学过那些类型的数据
整型,浮点型,字符型
所以应该这些相同类型的元素的的集合就是数组

int short long long char double float

一维数组的创建和初始化

数组的创建

//数组的创建
int arr[2];
char arr1[5];
double arr2[5];

总结:数据类型+数组名[常量表达式];
数据类型:指定数组类型
数组名:就像我们的变量名一样
常量表达式:指定元素个数,必须是常量表达式
在这里插入图片描述

数组的初始化
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)。 看代码:

//数组的创建和初始化
int arr1[2]={1,3};
int arr2[] = {1,2,3,4};   //未定义数组个数由初始化元素个数确定
int arr3[5] = {12345}char arr4[3] = {'a',98, 'c'};
char arr5[5]={'a','c','d','e','f'};
float arr5[3]={3.14,1.3,6.7};

总结

  • 数组在创建的时候如果想不指定数组的确定的大小就得初始化。
  • 数组的元素个数根据初始化的内容来确定。

但是对于下面的代码要区分,内存中如何分配?

//字符数组
char arr1[]="abcdef";  //字符串含'\0';
char arr2[]={'a','b','c','d','e','f'};

在这里插入图片描述可以看到数字初始化成字符串的形式,数组长度比,字符数组的形式多了一个\0的长度!

一维数组的使用

对于数组的使用我们之前介绍了一个操作符:[] ,下标引用操作符。它其实就数组访问的操作符。 我们来看代码:

#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++)//这里写10,好不好?
    {
        arr[i] = i;
    }   
    //输出数组的内容
    for(i=0; i<10; ++i)
    {
        printf("%d ", arr[i]);
    }
    return 0;
}

在这里插入图片描述

  • 数组的第一个元素的下标并不是arr[1],而是arr[0],数组的下标是从0开始访问的,如果有n个元素,那么最后一个元素的下标应该是arr[n-1]
  • 初始化的[]代表元素个数,而访问时[]代表的是下标。

一维数组在内存中的存储

int arr[10]={0,1,2,3,4,5,6,7,8,9};

可以看到数组arr在内存中的存储如下:
在这里插入图片描述
总结

  • 数组元素之间的地址是连续的且相差数组类型个字节(int类型相差4个字节,char类型1个字节)
  • 数组的第一个元素的地址就是数组的地址
  • 数组在内存中是连续存放的
    在这里插入图片描述

二维数组

二维数组本质上是以数组作为数组元素的数组,即“数组的数组”,类型说明符 数组名[常量表达式][常量表达式]

二维数组的创建和初始化

二维数组的创建

int arr1[5][5];
char arr2[3][5];
double arr[2][3];

二维数组的初始化

//从第一个元素开始初始化,未初始化的元素默认初始为0
int arr1[2][3]={1,2,3,4};
//按照每行初始化,每行未初始化的元素默认初始为0,
int arr2[2][3]={{1,2},{3,4}};
//根据初始化的行数确定数组的行数
int arr3[][3]={{1,2},{3,4}};

:初始化时,行号可以省略,列号不可省略

二维数组的使用

#include<stdio.h>
int main(void)
{
	int i = 0, j = 0;
	//初始化
	int arr[4][4] = { {1,2,3},{4,5,6},{7,8,9} };
	for (i = 0; i < 4; i++)
	{
		for (j = 0; j < 4; j++)
		{
			printf("%d ", arr[i][j]);
		}
		//换行
		printf("\n");
	}
	return 0;
}

在这里插入图片描述

二维数组在内存中的储存

二维数组像一维数组一样,这里我们尝试打印二维数组的每个元素!

#include <stdio.h>
int main()
{
    int arr[3][4];
    int i = 0;
    for(i=0; i<3; i++)
    {
        int j = 0;
        for(j=0; j<4; j++)
        {
            printf("&arr[%d][%d] = %p\n", i, j,&arr[i][j]);
        }
    }
    return 0;
}

在这里插入图片描述
通过结果我们可以分析到,其实二维数组在内存中也是连续存储的。
在这里插入图片描述

数组传参

一维数组作为函数参数

往往我们在写代码的时候,会将数组作为参数传个函数,比如:我要实现一个冒泡排序函数,将一个整形数组排序

//方法一
#include<stdio.h>
bubble_sort(int arr[])
{
  int i=0,j=0;
  int sz=sizeof(arr)/sizeof(arr[0]);
  int flag=0;
  for(i=0;i<sz-1;i++)
  {
    for(j=0;j<sz-1-i;j++)
    {
     if(arr[j]<arr[j+1])//降序
     {
       flag=1;
       int tmp=0;
       tmp=arr[j];
       arr[j]=arr[j+1];
       arr[j+1]=tmp;
     } 
     if(flag==0)
     break;
    }
  }
}
int main()
{
  int arr[]={1,3,5,7,2,6,4,8,10,9};
  bubble_sort(arr);//是否可以正常排序?
  int i=0;
  for(i=0;i<10;i++)
  {
  printf("%d ",arr[i]);
  }
}

在这里插入图片描述方法1,出问题,那我们找一下问题,调试之后可以看到bubble_sort 函数内部的sz ,是1
难道数组作为函数参数的时候,不是把整个数组的传递过去?
在这里插入图片描述
可以看到形参arr并不是数组,而是只有一个元素,sz=1,难道arr是地址?
在这里插入图片描述
可以看到在64位平台,sz=2验证了我们的猜测,arr就是地址,虽然形参是以arr[]数组的形式接收的,但还是地址,地址就只有4/8个字节。
所以数组长度只能在函数外部计算好传参进去!
数组名是什么
在这里插入图片描述

结论:

数组名是数组首元素的地址。(有两个例外)
在这里插入图片描述

如果数组名是首元素地址,那么:为什么输出的结果是:40
补充:

  1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。
    2.&数组名,取出的是数组的地址。&数组名,数组名表示整个数组。

除此1,2两种情况之外,所有的数组名都表示数组首元素的地址。

//改进后
#include<stdio.h>
void bubble_sort(int arr[],int sz)
{
  int i=0,j=0;
  int flag=0;
  for(i=0;i<sz-1;i++)
  {
    for(j=0;j<sz-1-i;j++)
    {
     if(arr[j]<arr[j+1])//降序
     {
       flag=1;
       int tmp=0;
       tmp=arr[j];
       arr[j]=arr[j+1];
       arr[j+1]=tmp;
     } 
     if(flag==0)
     break;
    }
  }
}
int main()
{
  int arr[]={1,3,5,7,2,6,4,8,10,9};
   int sz=sizeof(arr)/sizeof(arr[0]);
  bubble_sort(ar,sz);//是否可以正常排序?
  int i=0;
  for(i=0;i<sz;i++)
  {
  printf("%d ",arr[i]);
  }
}

在这里插入图片描述
我们已经知道,数组传参,数组名就是数组地址也是首元素地址,而我们用数组名接收或者数组接收得到的都是数组的地址;

//函数调用
bubble_sort(arr,sz);
//以数组接收1
bubble_sort(int arr[],int sz);
//以指针接收2
bubble_sort(int* arr,int sz);

既然我们用指针接收,那么我们就可以用指针的形式解引用!

void bubble_sort(int* arr,int sz)
{
  int i=0,j=0;
  int flag=0;
  for(i=0;i<sz-1;i++)
  {
    for(j=0;j<sz-1-i;j++)
    {
    // if(arr[j]<arr[j+1])//降序
     if(*(arr+j)<*(arr+j+1))
     {
       flag=1;
       int tmp=0;
       tmp=*(arr+j);
       *(arr+j)=*(arr+j+1);
       *(arr+j+1)=tmp;
     } 
     if(flag==0)
     break;
    }
  }
}

我们可以知道arr[1]等价于*(arr+1)

二维数组传参

二维数组,传参的方式和一维数组一样,但是数组名就不是,首元素地址了,而是首行地址,我们来验证一下。
在这里插入图片描述arr+1后地址向后走了16个字节,所以当我们二维数组以数组名传参后得到的是行指针。像一维数组一样,而我们肯定还要将二维数组的行列数传参才能控制二维数组。

//实现二维数组的打印
print(int arr[][3],int x,int y)
{
    int i=0,j=0;
  for(i=0;i<x;i++)
  {
  for(j=0;j<y;j++)
  {
    printf("%d ",arr[i][j]);
    //printf("%d ",*(*(arr+i)+j));  //地址的形式
  }
  printf("\n");
  }
}
int main()
{
 int  arr[4][3]={1,3,4,5,6,7,5,7,2,7,1,0};
 print(arr,4,3);
}

在这里插入图片描述
总结

  • 像二维数组的初始化一样,二维数组的形参行数不能省略。
  • 二维数组的数组名是第一行的行指针。
  • arr[i][j]等价于*( *(arr+i)+j)*(arr+i)解引用找到行指针存放的一行元素(一维数组)的地址,*( *(arr+i)+j)解引用找到该元素!
初阶数组就学习到这,我们后面还会利用我们所学的数组内容写三子棋和扫雷等小游戏巩固数组的学习,尽请期待.....还望大佬多多指点,有赞必回,,,!
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。