数组,作为C语言中常见的复杂数据类型,了解其本质有助于深入了解C语言

数组概念

元素类型角度:数组是相同类型的变量的有序集合测试指针变量占有内存空间大小

内存角度:联系的一大片内存空间

数组初始化

数组元素的个数可以显示或隐式指定

数组的初始化可以用{ 0 },也可以使用memset初始化

int main()
{
int i = 0;
int a[10] = { 1, 2 }; //其他初始化为0
int b[] = { 1, 2 };
int c[20] = { 0 }; for (i = 0; i < 10; i++)
{
printf("%d ", a[i]);
}
memset(a, 0, sizeof(a));
getchar();
return 0;
}

关于数组名的一些问题

  1. 数组首元素的地址和数组地址是两个不同的概念,前者代表一个元素大小,后者代表一个和数组大小
  2. 数组名代表数组首元素的地址,它是个常量,其本质就是一个变量的别名
  3. 数组首元素的地址和数组的地址值相等
  4. 数组的类型由元素类型和数组大小共同决定,e.g. int[5]

数组类型的自定义

typedef int(MYINT5)[5];
···
MYINT5i Array; //int Array[5];

数组指针

数组指针用于指向一个数组

  1. 通过数组类型定义数组指针
typedef int(ArrayType)[5];
ArrayType* pointer;

用数组类型加*定义一个数组指针

void main(void)
{
int a[5];//声明一个数组类型
typedef int(MYINT5)[5];//用数组类型 加*,定义一个数组指针变量
MYINT5 *array;
array = &a; for (i = 0; i < 5; i++)
{
(*array)[i] = i;
} for (i = 0; i < 5; i++)
{
printf("\n%d %d", a[i], (*array)[i]);
}
}
  1. 声明一个数组指针类型
typedef int (*MyPointer)[5];

定义一个数组指针类型,然后用类型定义变量

void main(void)
{
int b[5];//声明一个数组指针类型
typedef int (*MyPointer)[5];//用数组指针类型,去定义一个变量
MyPointer mypoint;
mypoint= &b; for (i = 0; i < 5; i++)
{
(*mypoint)[i] = i;
} for (i = 0; i < 5; i++)
{
printf("\n%d %d", b[i], (*mypoint)[i]);
}
}
  1. 直接定义
int (*pointer)[n];

直接定义一个数组指针变量

void main(void)
{
int c[5];
int (*pointer)[5] = &c;//直接声明一个数组指针变量
for (i = 0; i < 5; i++)
{
(*pointer)[i] = i;
} for (i = 0; i < 5; i++)
{
printf("\n%d %d", c[i], (*pointer)[i]);
}
}

一维数组本质

int a[5] 一维数组名代表数组首元素的地址

int a[5] ==> a的类型为int*

二维数组本质

实验:

int arr[3][4];
printf("arr:%d, arr + 1:%d", arr, arr + 1);

此时输出打印的结果相差16,也就是4 * 4,通过这个契机,得出二维数组名的本质

arr的本质是一个数组指针,每次向后移动一维的长度

说明 写法 写法 写法
第0行第1列元素地址 a [0]+1 *a+1 &a[0][1]
第1行第2列元素地址 a [1]+2 *(a+1)+2 &a[1][2]
第 i 行第 j 列元素地址 a [i]+j *(a+i)+j &a[i][j]
第1行第2列元素的值 *(a [1]+2) *( *(a+1)+2) a[1][2]
第 i 行第 j 列元素的值 *(a [i]+j) *( *(a+i)+j) a[i][j]

正是因为有了这些特性,二维数组在做函数参数的时候,会退化为二级指针,这样设计的目的在于参数传递的时候不用传递太多数据,数组指针做函数参数,一般只会使用到二维

char buf[3][4] ==> char buf[][4] ==> char (*buf)[4]

多维数组的线性存储特性

多维数组在内存中是线性存储的,即按照低维到高维线性排序

char buf[2][3];

buf[0][0]·buf[0][1]·buf[0][2]·buf[1][0]·buf[1][1]·buf[1][2]

数组做函数参数

由于C语言中只会以机械式的值拷贝的方式传递参数(实参把值传给形参),所以在数组做函数参数的时候,是没法知道数组大小的,需要额外传递数组大小数据

int fun(char a[20], size_t b)
{
printf("%d\t%d",b,sizeof(a));
}

二维数组可以看做是一维数组

二维数组中的每个元素是一维数组

二维数组参数中第一维的参数可以省略

void f(int a[5]); ==> void f(int a[]); ==> void f(int* a);

void g(int a[3][3]) ==> void g(int a[][3]); ==> void g(int (*a)[3]);

深入理解C语言-深入理解数组的更多相关文章

  1. 深入理解C语言-深入理解指针

    关于指针,其是C语言的重点,C语言学的好坏,其实就是指针学的好坏.其实指针并不复杂,学习指针,要正确的理解指针. 指针是一种数据类型 指针也是一种变量,占有内存空间,用来保存内存地址 指针就是告诉编译 ...

  2. 深入理解C语言-深入理解void

    void的字面意思是"无类型",void *则为"无类型指针",void *可以指向任何类型的数据 void含义 void几乎只有注释和限制程序的作用,定义一个 ...

  3. 深入理解C语言-深入理解内存四区

    数组与指针 当数组做函数参数的时候,会退化为一个指针 此时在函数内是得不到数组大小的 因此,数组做函数参数的时候需要传递数组大小,也就是多传递一个参数 void func(int arr[], int ...

  4. 深入理解C语言中的指针与数组之指针篇

    转载于http://blog.csdn.net/hinyunsin/article/details/6662851     前言 其实很早就想要写一篇关于指针和数组的文章,毕竟可以认为这是C语言的根本 ...

  5. 深入理解C语言中的指针与数组之指针篇(转载)

    前言 其实很早就想要写一篇关于指针和数组的文章,毕竟可以认为这是C语言的根本所在.相信,任意一家公司如果想要考察一个人对C语言的理解,指针和数组绝对是必考的一部分. 但是之前一方面之前一直在忙各种事情 ...

  6. 深入理解c语言_从编译器的角度考虑问题_纪念Dennis Ritchie先生

    开源中国: Dennis Ritchie教授过世了,他发明了C语言,一个影响深远并彻底改变世界的计算机语言.一门经历40多年的到今天还长盛不训的语言,今天很多语言都受到C的影 响,C++,Java,C ...

  7. "深入理解C语言" 指针

    本文对coolshell中的"深入理解C语言"这篇文章中提到的指针问题, 进行简要的分析. #include <stdio.h> int main(void){ ]; ...

  8. 理解C语言中指针的声明以及复杂声明的语法

    昨天刚把<C程序设计语言>中"指针与数组"章节读完,最终把心中的疑惑彻底解开了.如今记录下我对指针声明的理解.顺便说下怎样在C语言中创建复杂声明以及读懂复杂声明. 本文 ...

  9. 【转载】理解C语言中的关键字extern

    原文:理解C语言中的关键字extern 最近写了一段C程序,编译时出现变量重复定义的错误,自己查看没发现错误.使用Google发现,自己对extern理解不透彻,我搜到了这篇文章,写得不错.我拙劣的翻 ...

随机推荐

  1. e.target.value和this的区别

    1.e.target.value获取的就是你选择接受事件的元素输入的或者选择的值. 参数e接收事件对象. 而事件对象也有很多属性和方法,其中target属性是获取触发事件对象的目标,也就是绑定事件的元 ...

  2. struts2之多文件上传与拦截器(8)

    前台jsp <s:form action="uploadAction" enctype="multipart/form-data" method=&quo ...

  3. mysql自增主键清零方法

    MySQL数据库自增主键归零的几种方法 如果曾经的数据都不需要的话,可以直接清空所有数据,并将自增字段恢复从1开始计数: truncate table table_name; 1 当用户没有trunc ...

  4. MyEclipse运行项目出现 The user operation is waiting for "Building workspace" to complete

    如图所示 解决方式 1.选择菜单栏的“Project”,然后把菜单栏中“Build Automatically”前面的对钩去掉. 2.当你修改或添加代码后,选择菜单栏的“Project”,然后选择菜单 ...

  5. 在django中解决跨域AJAX

    由于浏览器存在同源策略机制,同源策略阻止从一个源加载的文档或脚本获取另一个源加载的文档的属性. 特别的:由于同源策略是浏览器的限制,所以请求的发送和响应是可以进行,只不过浏览器不接收罢了. 浏览器同源 ...

  6. centos7下面ruby的升级

    背景 在做redis集群时,所需要的使用ruby工具进行操作,发现在线安装的Ruby版本过低,redis支持的版本最少为2.2.2. 在线安装ruby 使用yum在线安装ruby,安装的版本为2.0. ...

  7. Leetcode题目236.二叉树的最近公共祖先(中等)

    题目描述: 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x,满足 x 是 p.q 的祖先 ...

  8. js实现回到顶部功能

    js实现回到顶部功能 一.总结 一句话总结: 可以通过js或者jquery可以很快的控制页面的属性,比如高度等等 //设置当前视口的顶端数值 var setScrollTop = function(t ...

  9. react 实现数据双向绑定

    好久没有更新了 只是都写在有道笔记中 今天整理下 一些基础的 大神勿喷 一个基础的不能再基础的数据双向绑定 因为react不同于vue 没有v-model指令 所以怎么实现呢? import Reac ...

  10. 性能测试 | 记一次生产数据库sql由451s优化为0.4s的过程

    概述 最近开发说某个接口跑的很慢,排查了下发现其中一条sql,数据量不大,但居然要跑451s,下面简单记录一下优化的过程. 问题sql SELECT l.location_gid ENUMVALUE, ...