数组(一篇带你掌握数组)

这篇具有很好参考价值的文章主要介绍了数组(一篇带你掌握数组)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

    在之前,我们想要存储一个数据的时候可以创建变量,例如存储一个整形的变量,我们使用int类型的变量来存储,那么如果存储一组相同类型的数据呢?这时我们就引入了数组的概念。

目录

一、一维数组的创建和初始化

1.1数组的创建

1.2 数组的初始化

1.3 一维数组的使用

1.4 一维数组在内存中的存储

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

2.1 二维数组的创建

 2.2 二维数组的初始化

2.3 二维数组的使用

2.4 二维数组在内存中的存储 

三、数组越界

四、数组作为函数参数

4.1 冒泡排序函数的错误设计

 4.2 冒泡排序函数的正确设计

4.3 数组名是什么

一、一维数组的创建和初始化

1.1数组的创建

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

数组的创建方式:

type_t arr_name[const_n];
//type_t 是指数组的元素类型 
// //arr_name 是数组名
//const_n 是一个常量表达式,用来指定数组的大小

例如我们想要存储10个int类型的数据,这时我们就可以创建一个数组来存储,即:int  arr[10];

在这里我们需要注意:

     数组创建,在C99标准之前,[ ]中要给一个常量才可以,不能使用变量,但是在C99中引入了变长数组的概念,变长数组支持数组的大小使用变量来指定,(变长数组不是数组的长度可以变化)。注意:变长数组不能初始化。

数组创建的例子:

int arr[10];
char arr1[10];
float arr3[1];
double arr4[10];

1.2 数组的初始化

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

例如:

int  arr[10] = { 1 };    //这种初始化方式是不完全初始化,指第一个元素初始化为1,其余的元                                    素默认初始化为0.

char arr1[3] = { 'a', 98, 'c' };      //将数组的第一个元素初始化为'a',第二个元素初始化为98,                                                    第三个元素初始化为'c'

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

两个初始化的比较:
 

#include <stdio.h>
int main()
{
	char ch1[10] = { 'a', 'b', 'c' };      //a b c 0 0 0 0 0 0 0
	char ch2[10] = "abc";        //a b c \0 0 0 0 0 0 0

	return 0;
}

数组(一篇带你掌握数组)

     在监视中我们发现ch1和ch2中存储的数据是一样的,但是其实他们的性质不同,ch1中第一个元素初始化为'a',第二个元素初始化为 'b',第三个元素初始化为'c',其余的元素默认初始化为0,而ch2中第一个元素初始化为'a',第二个元素初始化为'b',第三个元素初始化为'c',第四个元素初始化为'\0'(相当于0),其余元素默认初始化为0。

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

但是注意不要像下方的写法:

char ch1[] = "";

上述的初始化很容易出问题:
 

#include <stdio.h>
int main()
{
	char ch1[] = "";
	scanf("%s", ch1);

	printf("%s\n", ch1);
	return 0;
}

我们发现上述代码执行会报错:

数组(一篇带你掌握数组)

这是因为我们输入的字符长度超过了数组的长度
    char ch1[] = "";      在创建数组ch1时未指定大小数组的元素个数根据初始化的内容来确定,在这里我们使用空字符串初始化,空字符串中只有一个'\0',用'\0'初始化这个数组,这个数组的长度就是1,我们输入一个超过一个字符的字符串就会报错。

1.3 一维数组的使用

在这里我们要知道一个操作符:[ ],下标引用操作符,它其实就是用来访问数组的操作符。

我们需要知道数组的每一个元素都有对应的下标,并且数组的下标是从0开始的。

例如有一个数组   int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

数组(一篇带你掌握数组)

 我们访问元素通过下标来访问例如我们要访问数组的第5个元素我们就可以使用arr[4]来访问。

 我们可以将数组的每一个元素打印出来:

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

注意在这里的arr[i]表示数组的一个元素,而不是创建数组,访问数组元素可以使用变量。

总结:

  1. 数组是使用下标来访问的,下标是从0开始的。
  2. 数组的大小可以通过计算得到。即int sz = sizeof(arr) / sizeof(arr[0]);

1.4 一维数组在内存中的存储

我们要探讨一维数组在内存中的存储,就要看一维数组各元素的地址。

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (i = 0; i < sz; i++)
	{
		printf("&arr[%d] = %p\n",i, &arr[i]);
	}
	return 0;
}

数组(一篇带你掌握数组)

 数组(一篇带你掌握数组)

由此我们可以得出:数组在内存中是连续存放的

结论:

  1. 随着 数组下标的增长,元素的地址,也在有规律的递增。
  2. 数组在内存中是连续存放的。

数组(一篇带你掌握数组)

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

2.1 二维数组的创建

二维数组相当于是多了一个维度,例如:

我们想要创建一个数组,来存放三行四列的整型元素:int arr[3][4];

int arr[3][4]; 

数组(一篇带你掌握数组) 

 2.2 二维数组的初始化

两种方式:

     1.直接初始化,元素一个挨着一个初始化,初始化完一行再初始化一行,未放数据的元素初始化为     0

   例如int arr[3][4] = { 1, 2, 3, 4 };

     2.二维数组是可以指定第一行初始化为什么,第二行初始化为什么例如有三行四列的元素,我们想要把1,2初始化在第一行,3,4初始化在第二行,5初始化到第三行,(二维数组可以把他的一行当成一维数组,一维数组初始化用{ })因此我们这里可以int arr[3][4] = { { 1, 2 }, { 3, 4 }, { 5 } }

注意:
  二维数组如果有初始化,行可以省略,列不可以省略。

即:int arr[][3] = { { 2, 3 }, { 4, 5 } };

2.3 二维数组的使用

二维数组的使用也是通过下标的方式。

我们可以使用两种方式打印出来二维数组的元素:

按行打印:
 

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

数组(一篇带你掌握数组)

按列打印:

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

 数组(一篇带你掌握数组)

2.4 二维数组在内存中的存储 

要了解二维数组在内存中的存储,我们依然要去分析数组元素的地址。

#include <stdio.h>
int main()
{
	int arr[3][4] = { {1, 2},{3, 4},{5} };
	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;
}

数组(一篇带你掌握数组)

我们发现在内存中二维数组依然是连续存储的,即:

数组(一篇带你掌握数组) 

结论:

   二位数组在内存中也是连续存储的。

  数组(一篇带你掌握数组) 

三、数组越界

数组的下标是有范围限制的。

数组的下标是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。

所以数组的下标如果小于0,或者大于n-1,就是越界访问了,超出了数组合法空间的访问。

c语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,不代表程序是正确的,我们在写代码时需要自己做越界的检查。

越界会出现什么后果呢?
我们可以举例来看:

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

 数组(一篇带你掌握数组)

上述就是列越界的例子,会导致数组的读取紊乱,相当于:

数组(一篇带你掌握数组)
 

四、数组作为函数参数

在这里我们具体使用冒泡排序的例子来讲解 :

我们想要实现一个冒泡排序函数将一个整型数组排序。

冒泡排序的思想:
     两两相邻的元素进行比较,如果他们的顺序错误就把他们交换过来。一趟冒泡排序(把一组待排序的元素里面相邻的两个元素进行比较并且按照要求进行交换)之后最后一个位置放的是最大(最小)的数。

数组(一篇带你掌握数组)

 文章来源地址https://www.toymoban.com/news/detail-401956.html

4.1 冒泡排序函数的错误设计

#include <stdio.h>

void bubble_sort(int arr[])
{
	//求数组元素的个数
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		//一趟冒泡排序
		int j = 0;
		for (j = 0; j <sz-1-i ; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

int main()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	//0 1 2 3 4 5 6 7 8 9
	//要对数组升序排序
	//冒泡排序
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

我们发现代码会报错

数组(一篇带你掌握数组)

我们来分析错误原因:
数组(一篇带你掌握数组) 

    所以在这里我们知道是由于数组名传参的时候传递的是首元素的地址导致sz无法计算最终程序错误。

 4.2 冒泡排序函数的正确设计

上述代码错误是由于sz在自定义函数内部的计算错误,那么我们可以根据此处改进:
 

#include <stdio.h>

void bubble_sort(int arr[],int sz)
{
	
	int i = 0;
	for (i = 0; i < sz - 1; i++)
	{
		//一趟冒泡排序
		int j = 0;
		for (j = 0; j <sz-1-i ; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

int main()
{
	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
	//0 1 2 3 4 5 6 7 8 9
	//要对数组升序排序
	//冒泡排序
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr,sz);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

我们直接将sz的值传参过去,避免了在自定义函数内部的计算。

4.3 数组名是什么

数组名是首元素的地址(有两个例外)。

  1. sizeof(数组名),计算整个数组的大小,数组名表示整个数组,单位是字节。
  2. &数组名,数组名表示整个数组,取出的是整个数组的地址。

除了上述情况以外,所有的数组名都表示数组首元素的地址。

在这里,我们介绍一下上述2与其他的区别:
数组(一篇带你掌握数组)

 数组的地址也是首元素的地址所以这里相同。

不同:

数组(一篇带你掌握数组)

 

到了这里,关于数组(一篇带你掌握数组)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】一篇带你彻底吃透 顺序表

    顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改等功能。 顺序表一般可以分为: 静态顺序表:使用定长数组存储元素。 动态顺序表:使用动态开辟的数组存储。 而现实的顺序表大多数采用动态

    2023年04月19日
    浏览(81)
  • [Linux 基础] 一篇带你了解linux权限问题

    Linux下有两种用户:超级用户(root)、普通用户。 超级用户:可以再linux系统下做任何事情,不受限制 普通用户:在linux下做有限的事情。 超级用户的命令提示符是“#”,普通用户的命令提示符是“ $ ” 命令: su [用户名] 功能: 切换用户。 例如,要从root用户切换到普通用

    2024年02月08日
    浏览(48)
  • 【C语言】-- 一篇带你了解指针,内存,解引用

    目录 1、什么是指针? 1.1 内存 1.2 指针变量 二、指针和指针类型 1、指针类型 2、指针+整数 3、指针的解引用 三、野指针 1、野指针成因 (1) 指针未初始化 (2) 指针越界访问 (3) 指针指向的空间释放 2、如何规避野指针 四、指针运算 1、指针-指针        本篇文章我们来了解C语

    2024年02月16日
    浏览(58)
  • Linux - 一篇带你读懂 Curl Proxy 代理模式

    curl 是一个很有名的处理网络请求的 类Unix 工具。出于某种原因,我们进行网络请求,需要设置代理。本文讲全面介绍如何为 curl 设置代理 设置代理参数 基本用法 设置 HTTP 代理 下面两种设置代理的方式是可以的 由于代理地址的默认协议为  HTTP, 所以可以省略,按照下面的

    2024年02月05日
    浏览(69)
  • 【Mysql】一篇带你了解数据定义,操作和查询语言

    目录 数据定义语言DDL(Data Definition Language) 一.对数据库的操作 二.对数据表的操作 数据操作语言DML(Data Manipulation Language) 一.添加 insert into 二.删除  delete 三.修改  update 数据查询语言DQL(Data Query Language) 一.查询 select 二. 1.between ... and ...(在....之间) 2.in, exists

    2024年02月12日
    浏览(86)
  • C语言学习系列-->一篇带你看懂内存函数

    上篇文章学习了C语言字符串函数,只是对字符串进行操作 本节,小编整理了一下C语言中的内存函数,对内存进行操作,只针对会内存块,不针对数据 memcpy是对内存拷贝 拷贝的可能是字符串,也可能是整型数组 所以使用 void* 将source拷贝到destination,指定字节数为num code arr

    2024年02月09日
    浏览(49)
  • [ C++ ] 一篇带你了解C++中隐藏的this指针

    本篇文章我们将一起讨论在有趣的知识点--隐藏的this指针。本篇我们要使用到之前我们所学习到的C++类与对象(1),如果有各位小伙伴还不曾了解类与对象的简单思想,可以访问上篇博客:[ C++ ] 带你一篇了解什么是OOP(面向对象编程),什么是封装? -- 类与对象(上) 目录 1.

    2024年02月07日
    浏览(57)
  • Vue详解----一篇带你从头领悟到尾,享受飞升的感觉

    \\\"\\\"\\\" \\\"\\\"\\\" vue.js与vue.runtime.xxx.js的区别: vue.js是完整版的Vue,包含:核心功能 + 模板解析器。 vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template这个配置项,需要使用render函数接收到的createElement函数去指

    2024年02月16日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包