c回顾之数组

191人阅读 评论(0) 收藏 举报

数组解析与总结

#include<stdio.h>
#include<string.h>
#include<Windows.h>


void bubble_one_i(int bu[], int size0);
void bubble_one_d(double bu1[], int size1);
void bubble_two(int bu2[][8], int size2);
void bubble_more(int bu3[][6][7][8], int size3);

int main()
{
	//数组是一种类型(聚合数据类型):只有类型才能定于变量,开辟空间
	int arr[] = { 1, 2, 3, 4, 5 };
	//[]:是常量表达式(必须>0),只能是整型或宏定义(建议使用宏定义)
	//此常量表示数组中元素的个数,所以此处默认为5
	int size = sizeof(arr) / sizeof(arr[0]);

	char arr1[] = { 'a', 99, 'e' };//字符数组在内存中都以数字的形式存储
	printf("%c\n", arr1[0]);//区别在于输出形式
	printf("%d\n", arr1[0]);

	char arr2[] = "abcdefg";//一个字符串始终以'\0'结尾
	//arr2等价于:{'a','b','c','d','e','f','\0'}
	printf("%d\n", strlen(arr2));//而其长度则不将'\0'计入,结果为7
	printf("%d\n", sizeof(arr2) / sizeof(arr2[0]));
	//但其大小将'\0'计入(原因:大小是指给其开辟的内存空间),结果为8

	char *p = "abcdefg";//内存开辟4个空间
	//在32位的平台上指针变量开辟4个空间:2的32次方个地址->32个比特位+8位1字节->一个地址则需要4个字节存放
	//用字符指针定义字符串,字符串的首元素地址被放入p中,而字符串整体被放在字符常量区,所以在栈区仅开辟4个字节

	int arr3[] = { 1, 2, 3, 4, 5, };//最后一个元素后面的逗号可要可不要,对数组长度无影响
	//对于数组的赋值:只有在数组初始化的时候可以整体直接赋值(即用{}整体赋值);
	//arr3 = { 5, 6, 7, 8, 9 };//错误:不可以二次整体赋值
	//但不可以二次整体赋值


	//数组在内存中的存储
	//数组开辟的空间是连续的,从arr[0]到arr[size-1]是递增的
	//原因
	int i = 5;//一个int型的变量在内存中占4个字节,即为4个地址
	int *p1 = &i;//而p1中只能存放一个地址,监视可知存放的是低地址
	//而int这个类型决定了此地址后续的共4个地址整个被当做是一个整型
	int arr4[] = { 1, 2, 3, 4, 5};
	int *p2 = &arr4;
	//同理:数组也是一个类型,此时p2中存放的也是整个数组开辟空间的最低地址
	//而最低地址的后续5*4个地址整体被当做是一个数组//类型决定看待内部地址内容的一个方式
	//由此可知:所有的类型存放均是递增的
	
	int arr5[] = { 1, 2, 3, 4};
	printf("%p\n", arr);//数组的数组名在做右值或做运算时代表数组首元素的地址
	printf("%p\n", &arr);//数组的地址
	printf("%p\n", &arr[0]);//数组首元素的地址
	//上三者的输出相同:数组的地址在数值上默认和数组首元素的地址是相等的(但在类型上不一致)
	//右值:代表存储内容;左值:代表存储空间
	printf("%d\n", *arr);//如上所说:则*arr代表对数组首元素地址进行解引用
	printf("%p\n", arr + 1);//代表数组第二个元素的地址等价于&arr[1]
	printf("%d\n", *(arr + 1));//代表第二个元素等价于arr[1]
	for (int j = 0; j < sizeof(arr5) / sizeof(arr5[0]); j++){
		printf("%d\t", *(arr + j));//数组名+整数:获取到每个元素的地址
	}
	printf("\n");

	//二维数组:也是一种类型,所以在内存中也是连续递增存放的
	int arr6[][4] = { { 1, 2, 3 }, { 0 } };//第一个[]代表此二维数组中有多少个元素(可省略)
	//第二个[]代表每个元素(即为一维数组:每个{}括起来的都标识一个一维数组)的长度(不可省略)
	//所以二维数组也可以理解为是一个存放多个一维数组的一维数组
	printf("%p\n", arr6);//首元素的地址(地址就是指针):首元素即为一个一维数组
	printf("%p\n", &arr6 + 1);//下一个二维数组的地址(&arr6代表这个数组的地址),与&arr6相差32:指针-/+整数实质是-/+指针所指类型的大小

	int *p3 = &arr6[0][0];
	//通过指针向二维数组赋值
	for (int k = 0; k < 2 * 4; k++){
		*(p3 + k) = k;//二维数组是连续存放的
	}

	//一维数组的练习
	//1
	int arr7[] = { 1, 2, 3, 4 };
	printf("%d\n", sizeof(arr7));//4*4 = 16
	printf("%d\n", sizeof(arr7 + 0));//&arr7[0]:4
	printf("%d\n", sizeof(*arr7));//*&arr7[0] = arr7[0] = 1:4
	printf("%d\n", sizeof(arr7 + 1));//&arr7[1]:4
	printf("%d\n", sizeof(arr7[1]));//2:4
	printf("%d\n", sizeof(&arr7));//数组的地址:4
	printf("%d\n", sizeof(*&arr7));//对数组整个的地址进行解引用:整个数组:16
	printf("%d\n", sizeof(&arr7 + 1));//跳过整个数组的下一个地址:4
	printf("%d\n", sizeof(&arr7[0]));//4
	printf("%d\n", sizeof(&arr7[0] + 1));//&arr7[1]:4
	//数组名在sizeof和&时代表整个数组//重中之重!!!
	//数组名在做右值或做运算时代表数组首元素的地址//重中之重!!!
	//&arr+1与&arr相差16个字节(整个数组)
	//arr+1与arr相差4个字节(数组中的一个元素)
	printf("\n");

	//2
	char arr8[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
	//sizeof:求数组大小
	printf("%d\n", sizeof(arr8));//6*1 = 6
	printf("%d\n", sizeof(arr8 + 0));//&arr8[0]:4
	printf("%d\n", sizeof(*arr8));//*&arr8[0] = arr8[0] = 'a':1
	printf("%d\n", sizeof(arr8[1]));//'b':1
	printf("%d\n", sizeof(&arr8));//数组的地址:4
	printf("%d\n", sizeof(&arr8 + 1));//跳过整个数组的下一个地址:4
	printf("%d\n", sizeof(&arr8[0] + 1));//&arr8[1]:4
	printf("\n");

	//strlen:求字符串的长度
	//strlen接收一个char*的参数(以'\0'结束但计算长度不包括'\0')
	printf("%d\n", strlen(arr8));//由于此字符数组没有'\0'而strlen是求一个字符串的长度
	//而在c语言的定义中,字符串是以'\0'结尾的,所以此处的长度是遇到内存中的'\0'而结束所计算的长度
	//即为随机值,但此随机值必然>=6,此次编译为17
	printf("%d\n", strlen(arr8 + 0));//&arr8[0]:从首元素到结束:结果同上:17
	//printf("%d\n", strlen(*arr8));//*&arr8[0] = arr8[0] = 'a':报错
	//printf("%d\n", strlen(arr8[1]));//'b':报错
	printf("%d\n", strlen(&arr8));//数组的地址:同上:17
	printf("%d\n", strlen(&arr8 + 1));//跳过整个数组的下一个地址:则从此地址到内存中'\0'结束的长度:17-6 = 11
	printf("%d\n", strlen(&arr8[0] + 1));//&arr8[1]:从第二个元素到'\0'结束的长度:17-1 = 16
	printf("\n");

	//3
	char arr9[] = "abcdef";
	//sizeof求字符串的大小包括'\0'
	printf("%d\n", sizeof(arr9));//7
	printf("%d\n", sizeof(arr9 + 0));//&arr9[0]:4
	printf("%d\n", sizeof(*arr9));//*&arr9[0] = arr9[0] = 'a':1
	printf("%d\n", sizeof(arr9[1]));//'b':1
	printf("%d\n", sizeof(&arr9));//数组的地址:4
	printf("%d\n", sizeof(&arr9 + 1));//下一个数组的地址(跳过整个数组的下一个地址):4
	printf("%d\n", sizeof(&arr9[0] + 1));//&arr9[1]:4
	printf("\n");

	//strlen:求字符串的长度
	//strlen接收一个char*的参数(以'\0'结束但计算长度不包括'\0')
	printf("%d\n", strlen(arr9));//字符串默认以'\0'结尾,没有的话编译器会默认加上:6
	printf("%d\n", strlen(arr9 + 0));//&arr9[0]:从首元素到结束:结果同上:6
	//printf("%d\n", strlen(*arr9));//*&arr9[0] = arr9[0] = 'a':报错
	//printf("%d\n", strlen(arr9[1]));//'b':报错
	printf("%d\n", strlen(&arr9));//数组的地址:同上:6
	printf("%d\n", strlen(&arr9 + 1));//下一个数组的地址(跳过整个数组的下一个地址):则从此下一个地址到内存中下一个'\0'结束的长度
	//此次编译为25
	printf("%d\n", strlen(&arr9[0] + 1));//&arr9[1]:从第二个元素到'\0'结束的长度:6-1 = 5
	printf("\n");

	//4
	char *p4 = "abcdef";//p4指向此字符串常量,此时p4中存放的是a(即为字符串首元素)的地址
	//注意:指针的数组无关!!!
	printf("%d\n", sizeof(p4));//字符串第一个元素的地址&a:4
	printf("%d\n", sizeof(p4 + 1));//&b :4
	printf("%d\n", sizeof(*p4));//*&a = 'a':1
	printf("%d\n", sizeof(p4[0]));//'a':1
	printf("%d\n", sizeof(&p4));//指针p的地址:4
	printf("%d\n", sizeof(&p4 + 1));//跳过存放指针的下一个地址(存放p变量的下一个地址):4
	printf("%d\n", sizeof(&p4[0] + 1));//&b:4
	printf("\n");

	printf("%d\n", strlen(p4));//字符串的第一个元素到末尾的'\0'的长度:6
	printf("%d\n", strlen(p4 + 1));//从b位置到末尾的'\0'的长度:6-1 = 5
	//printf("%d\n", strlen(*p4));//*&a = 'a':1//报错
	//printf("%d\n", strlen(p4[0]));//'a':1//报错
	printf("%d\n", strlen(&p4));//指针p的地址:从存放指针的地址开始到内存中下一个'\0'结束的长度
	//此次编译为3
	printf("%d\n", strlen(&p4 + 1));////跳过存放指针的下一个地址,则从此下一个地址到内存中下一个'\0'结束的长度
	//此次编译为25
	printf("%d\n", strlen(&p4[0] + 1));//从b位置到末尾的'\0'的长度:6-1 = 5
	printf("\n");

	//二维数组练习
	int arr10[3][4] = { 0 };
	printf("%d\n", sizeof(arr10));//3*4*4 = 48
	printf("%d\n", sizeof(arr10[0][0]));//第一个元素(一维数组int [])的第一个元素(int):4
	printf("%d\n", sizeof(arr10[0]));//第一个元素(一维数组int []):4*4 = 16
	printf("%d\n", sizeof(arr10[0] + 1));//注意!!!arr10[0]代表第一个元素,而第一个元素是一个一维数组
	//一维数组的数组名+1:代表&arr10[0][0]+1,则其代表&arr10[0][1]:4
	printf("%d\n", sizeof(arr10 + 1));//第二个元素(一维数组int [])的地址:4
	printf("%d\n", sizeof(&arr10[0] + 1));//第二个元素的地址:4
	printf("%d\n", sizeof(*arr10));//*&arr10[0] = arr10[0] :4*4 = 16
	printf("%d\n", sizeof(arr10[3]));//注意!!!结果正常输出16
	//原因:允许访问和比较数组最后一个元素的下一个元素,但不允许写入

	//数组名在sizeof和&时代表整个数组//重中之重!!!
	//数组名在做右值或做运算时代表数组首元素的地址//重中之重!!!


	//关于数组传参
	/*
	1、任何数组都是一维数组
	2、一维数组传参时会降维:(作用)减少开销
	3、会降维成指向其内部元素类型的一级指针
	*/
	//一维数组传参
	int bu[5];
	int size0 = sizeof(bu) / sizeof(bu[0]);
	bubble_one_i(bu ,size0);

	double bu1[5];
	int size1 = sizeof(bu1) / sizeof(bu1[0]);
	bubble_one_d(bu, size1);

	//二维数组传参
	/*
	二维数组传参时,第一个[](代表该数组的长度)可以不写,其余必须补充完整
	原因:数组传参时都会降维成指向其内部类型的一级指针,而二维数组是内部元素为一维数组的一维数组
	而第二个[]代表内部元素一维数组的元素个数,所以内部类型必须完整!!!
	*/
	int bu2[7][8];
	int size2 = sizeof(bu2) / sizeof(bu2[0]);
	bubble_two(bu2, size2);

	//多维数组传参:要保证数组内部类型的完整,所以后三个[]必须完整!!!
	int bu3[5][6][7][8];//四维数组:存放5个三维数组的一维数组
	int size3 = sizeof(bu3) / sizeof(bu3[0]);//适用于任何数组
	bubble_more(bu3, size3);

	system("pause");
	return 0;
}

void bubble_one_i(int bu[], int size0)//一维数组传参时,[]中会被忽略,可不写
{
	printf("%d\n", sizeof(bu));//4:降维成整型一级指针
}

void bubble_one_d(double bu1[], int size1)//一维数组传参时,[]中会被忽略,可不写
{
	printf("%d\n", sizeof(bu1));//4:降维成双精度浮点型一级指针
}

void bubble_two(int bu2[][8], int size2)//此处等价于int (*)[4]
{
	printf("%d\n", sizeof(bu2));//4:降维成一维数组类型的一级指针
}

void bubble_more(int bu3[][6][7][8], int size3)//此处等价于int (*)[6][7][8]
{
	printf("%d\n", sizeof(bu3));//4:降维成三维数组类型的一级指针
}

查看评论

黑马程序员——iOS核心基础(7-8天)

C语言基础7-8天。知识点回顾、初识数组与排序。
  • 2015年06月29日 18:32

《C专家编程》:全面回顾认识C++(十)

如果你觉得C++还不够复杂,那你知道protected abstract virtual base pur virtual private destructor inheritance是什么意思吗?你...
  • gogoky
  • gogoky
  • 2016-06-19 15:12:03
  • 1945

《C专家编程》学习笔记

最近在看《C专家编程》这本书,网上的评价还是挺高的,上面一些知识我还是知道些,...
  • formula27
  • formula27
  • 2014-05-07 22:13:41
  • 704

敏捷其实很简单(15) 回顾会议

其实个人以为,回顾会议在scrum所有的events中是最重要的一个 正如上图所示,我们可以看到在整个scrum的价值流上,每个会议都有不同的对应意义:planning meeting用来将目标分解...
  • superkunkun
  • superkunkun
  • 2017-01-09 21:33:15
  • 1399

敏捷趣味回顾会议-回顾

快乐与收益 (#1) 快乐与收益活动是一个非常棒的活动,用来谈论所有工作相关的事情,工作如何影响每个参与者(有关快乐与否),以及工作给团队带来多少收益。 开展活动: 1.     画出快乐与收益图 ...
  • huver2007
  • huver2007
  • 2017-09-14 09:15:29
  • 475

Scrum之 回顾会议

Scrum中Sprint计划会议是最重要的事件,第二重要的事件就是回顾会议,因为这是团队做改进的最佳时机。如果没有回顾,就会发现团队在重犯相同的错误。在sprint的评审会议后,团队需要进行一次回顾会...
  • SUKHOI27SMK
  • SUKHOI27SMK
  • 2015-03-10 09:55:20
  • 1541

敏捷回顾会:经验教训的总结

敏捷回顾会:经验教训的总结 原文:Agile Retrospectives: Lessons Learned 在一个sprint中哪些方面做得好,哪些方面做得不好,哪些方面需要提高?在每一个敏...
  • maifansnet
  • maifansnet
  • 2017-11-02 21:02:59
  • 584

项目回顾案例

某公司从2015年6月下旬开始启动了一个敏捷开发的项目,截止到8月中旬结束,投入的开发人员、测试人员、管理人员达到60多人,2015年8月31日,由咨询顾问作为主持人带领该团队的10多名核心人员,对整...
  • dylanren
  • dylanren
  • 2015-09-09 11:10:07
  • 3616

黑马程序员-c语言回顾-数组

一维数组,二维数组,冒泡排序,选择排序。
  • Mr_Right_777
  • Mr_Right_777
  • 2015-09-13 08:50:25
  • 491

C语言回顾 四 数组

数组是一种构造类型,相同数据类型构成新的数据类型。数组的每个成员成为一个数组元素。 最简单的数组是:一位数组。 一维数组的定义: 类型说明符 数组名【常量表达式】 = {值1,值2......}; 在...
  • Zero_Jones
  • Zero_Jones
  • 2015-10-14 12:58:56
  • 363
    个人资料
    持之以恒
    等级:
    访问量: 6842
    积分: 450
    排名: 11万+
    文章分类
    最新评论