文档章节

C语言的数组和指针_《C专家编程》读书笔记

AllenOR灵感
 AllenOR灵感
发布于 2017/09/10 01:02
字数 1952
阅读 2
收藏 0

数组和指针并不是一回事。


什么是定义,什么是声明

定义:

     特点:只能出现在同一个地方
     作用:确定对象的类型并且为其分配内存,用于创建新的对象,例如:int my_array[100];

声明

    特点:可以出现多次      
    作用:描述对象的类型,用于指代其他地方定义的对象,例如:extern int my_array[];

如何区分定义和申明

   声明相当于普通的声明:它所说明的并非自身,而是描述其他地方的创建的对象。
   定义是特殊的声明:它在定义的时候已经分配了内存空间。

extern对象的声明告诉编译器对象的类型和名字,对象的内存分配在别处进行。由于并未在声明中为数组分配空间。随意不需要提供关于数组长度的信息,对于多维数组,需要提供除了左边第一维之外的其他维度的长度 ——这就给了编译器足够的信息产生相应的代码。


数组和指针如何访问。

什么是左值,什么是右值:

1:什么是“地址y”“地址y的内容”,这是一个非常微妙的地方,在大多数的语言中使用同一个符号来表示这两样东西。编译器会根据上下文环境来判断他的具体含义。
以一个简单的赋值为例:
X=Y;
首先看看X:
在这个上下文中,X的含义是X所代表的地址,这被称为左值,左值在编译时可知,左值表示存储结果的地方。
再看看Y:
在这个上下文环境中,Y的含义是Y所代表的地址的内容。这被称为右值,右值直到运行时才知,如无特别说明,右值表示“Y的内容”。

   C语言引入了“可修改左值”这个术语,它表示左值允许出现在赋值语句的左边,这个概念是为了与数组名区分,数组名也用于确定对象在内存中的位置,也是左值。但是它不能作为赋值对象。因此,数组名这个左值是左值但是不是可以修改的左值。通俗地讲,只能给可以修改的东西赋值。

数组下标的引用

数组的下标引用
数组的下标引用
   具体过程:
   char a[9]="abcdefgh"; ... c=a[i];
   编译器符号表具有一个地址9980
       运行时步骤1:取i的值,将它与9980相加
       运行时步骤2:取得地址(9980+i)的内容

这就是为什么extern char a[]与extern char a[100]等价的原因。这两个声明都表示a是一个数组,也就是一个内存地址,数组内的字符可以从这个地址找到。编译器不需要知道数组到底有多长,因为它只会产生偏离起始地址的偏移地址。从数组取一个数字符,只要简单地从符号表显示的a地址加上下标,需要的字符就在这个地址中。


对指针的引用

相反,如果声明extern char*p,它将会告诉编译器p是一个指针,它实现的对象是一个字符,为了取得这个字符,必须得到地址p的内容,把它作为字符的地址并且从这个地址中取得这个字符,指针的访问要灵活很多,但是需要增加一次额外的提取。


对指针的引用
对指针的引用
具体过程:
char*p ...  c=*p;
编译器符号表有一个符号p,它的地址为4624
       运行时步骤1:取地址4624的内容,就是‘5081’
       运行时步骤2:取地址5081的内容。

定义指针但是以数组方式引用

现在看一下当一个外部数组的实际定义是一个指针,但是却以数组的方式对其引用时,会引起什么问题。需要对内存进行直接引用,但是这时编译器所执行的是对内存进行间接引用,之所以会如此,是因为我告诉编译器我们拥有的是一个指针。


对指针进行下标引用
对指针进行下标引用
具体过程:
char*p="abcdefgh";    ...    c=p[i];
编译器符号表具有一个p,地址为4624
       运行时步骤1:取地址4624的内容,即‘5081’。
       运行时步骤2:取得i的值,并且将它与5081相加。
       运行时步骤3:取地址[5081+i]的内容。

数组和指针其他的区别

指针 数组
保存数据的地址 保存数据
间接访问数据,首先取得指针的内容,把它作为地址,然后从这个地址提取数据如果指针有一个下标[I],就把指针的内容加上I作为地址,从中提取数据 直接访问数据,a[I]只是简单地以a+I为地址取得数据。
通常用于动态数据结构 通常用于存储固定数目且数据类型相同的元素
相关的函数为malloc(),free() 隐式分配和删除
通常指向匿名数据 自身即为数据名

数组和指针指向字符串时

数组和指针都可以在它们的定义中用字符串常量进行初始化,尽管看上去一样但是底层的实现机制却不同。

指针

定义指针时,编译器并不为指针所指向的对象分配空间,它只是分配指针本身的空间,除非在定义的同时赋给指针一个字符串常量进行初始化,

char *p="breadfruit";

注意只有字符串常量才是如此,不能指望其为浮点数之类的常量分配空间,如:

float *pip=3.141;/* 错误,无法通过编译*/

在ANSI C 中初始化指针时所创建的字符串常量被定义为只读,如果试图通过指针修改这个字符串的值,程序就会出现未定义的行为。在游戏编译器中,字符串常量被存放在只允许读取的文本段中,以防止它被修改。

数组

数组也可以用字符串常量进行初始化:

char a[]="gooseberry";

与指针相反,由字符串常量初始化的数组是可以修改的,其中单个字符在以后可以改变,比如下面的语句:

strncpy(a,"black",5);

就将数组的值修改为“blackberry”

什么时候数组和指针相同

在实际的应用中数组和指针可以交换的情况要比两者不能交换的情况更为常见。
让我们分别考虑“声明”和“使用”这两种情况
1:声明
1) 外部数组的声明
2) 数组的定义(记住,定义是声明的一种特殊情况,它分配内存空间,并可能提供一个初始值)。
3) 函数参数的声明
所有作为函数参数的数组名总是可以通过编译器转换为指针。
数组的声明就是数组,指针的声明就是指针,两者不能混淆,数组总是可以写成指针的形式两者可以互换。

什么时候数组和指针相同
什么时候数组和指针相同

数组和指针参数是如何被编译器修改的
实参 所匹配的参数
数组的数组 char c[8][10] ; char(*)[10];数组指针
指针数组 char *c[15] ; char **c; 指针的指针
数组指针(行指针) char(*c)[64]; char (*c)[64] 不改变
指针的指针 char **c; char **c;不改变

本文转载自:http://www.jianshu.com/p/06cad24717f9

AllenOR灵感
粉丝 11
博文 2635
码字总数 83001
作品 0
程序员
私信 提问
复杂声明 | C语言

今天看了《C专家编程》里的'分析C语言的声明'一章,终于懂了C语言的复杂声明是怎么解析的。虽然在平时写代码的时候用到复杂声明的情况几乎没有,这里还是做一个记录,也是加深对C语言声明的理...

好好编程
2018/01/16
0
0
Redis设计与实现系列-基本数据结构-链表和压缩列表

关于《Redis设计与实现》读书笔记 链表作为一种非常友好的数据结构在很多高级编程语言中都有内置,然而C语言中没有没有链表这种数据结构,在redis中redis自行设计了一套链表数据结构用于存储...

申文波
2018/07/31
11
0
《C Primer Plus》读书笔记——数组和指针(1)

背景 此章笔记以读者有简单的C语言基础,对数组(array)、指针(pointer)有初步了解及应用,想扎实基础或深入探究为背景而写。 数组的使用 举个栗子: 输出如下: 用标识符常量表示数组大小...

cugwyman
2017/02/06
0
0
《大话数据结构》读书笔记(1)

其实去年的时候就看过这本书了。只是,基本上是走马观花, 了解了一些基本概念。这次,为了看懂里面的代码,又特地去复习了一下c语言。还记得上次看的时候,感觉算法果然名不虚传,真的难!现...

幽灵君
2018/12/16
0
0
C++雾中风景番外篇:理解C++的复杂声明与声明解析

在学习C系列语言的过程之中,理解C/C++的复杂声明一直是初学者很困扰的问题。笔者初学之时也深受困扰,对很多规则死记硬背。后续在阅读《C专家编程》之后,尝试在编译器的角度来理解C/C++的声...

LeeHappen
2018/09/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周日乱弹 —— 我,小小编辑,食人族酋长

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @宇辰OSC :分享娃娃的单曲《飘洋过海来看你》: #今日歌曲推荐# 《飘洋过海来看你》- 娃娃 手机党少年们想听歌,请使劲儿戳(这里) @宇辰OSC...

小小编辑
58分钟前
121
7
spring cloud

一、从面试题入手 1.1、什么事微服务 1.2、微服务之间如何独立通讯的 1.3、springCloud和Dubbo有哪些区别 1.通信机制:DUbbo基于RPC远程过程调用;微服务cloud基于http restFUL API 1.4、spr...

榴莲黑芝麻糊
今天
2
0
Executor线程池原理与源码解读

线程池为线程生命周期的开销和资源不足问题提供了解决方 案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。 线程实现方式 Thread、Runnable、Callable //实现Runnable接口的...

小强的进阶之路
昨天
6
0
maven 环境隔离

解决问题 即 在 resource 文件夹下面 ,新增对应的资源配置文件夹,对应 开发,测试,生产的不同的配置内容 <resources> <resource> <directory>src/main/resources.${deplo......

之渊
昨天
8
0
详解箭头函数和普通函数的区别以及箭头函数的注意事项、不适用场景

箭头函数是ES6的API,相信很多人都知道,因为其语法上相对于普通函数更简洁,深受大家的喜爱。就是这种我们日常开发中一直在使用的API,大部分同学却对它的了解程度还是不够深... 普通函数和...

OBKoro1
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部