数组在内存中以顺序的形式存放,数组的第一个存储单元的地址即数组的首地址。对一维数组来说,直接引用数组名就能获得该数组的首地址。指针变量可以存放于其内容相同的数组首地址,也可以指向某一具体的数组元素。通过这种方式,多维数组也被看作一维数组来操作,简化了数组的操作方式。

4.6.1 指针 与 一维数组

定义一维数组后,可定义一个与其类型相同的指针变量指向该数组。如:

int i[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, *pi;		// 定义整型数组 i 和整型指针变量 *pi
pi = i; // 将指针变量 *pi 指向数组 i 的首地址

这样 *pi 就指向了数组 i 的第一个单元,该赋值操作等同于 “pi = &i[0]”,pi 与数组 i 的关系型如图 8.7 所示。如果对指针内的地址进行运输,指向“pi +=4”,则 pi 的指向关系随之发生改变,如图 8.8 所示。

因此,可以将 C 语言指针指向一维数组的方法总结为以下 3 条:

(1)、“pi + n”或“i + n”表示数组元素 i[n] 的地址,即“&i[n]”。数组 i 有 10 个元素,n 的取值为 0 至 9,则数组的地址可表示为“pi + 0”至“pi + 9”,或“i + 1”至“i + 9”,与 &i[0] 至 &i[9] 的作用一样;

(2)、知道了数组元素的地址表示方法,“*(pi + n)”;

(3)、指向数组的指针变量也可用数组的下标形式表示为 pi[n],其效果相当于“*(pi + n)”。

4.6.2 指针 与 二维数组

二维数组和其他多维数组都能看作一维数组进行指针操作 。如下例所示:

int i[2][5] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, *pi; // 定义整型二维数组 i 和 整型指针变量 pi
pi = i[0]; // 将指针变量 pi 指向数组 i 的首地址

该数组可以视作一个表格,数组 i 与 pi 的关系如图 8.9 所示。如果要访问其中的元素 i[1][2],则可用公式 1 x n + 2 得到该元素的位置,引用时可写作 “*(pi + 1 * n + 2)”。

二维数组的每一行都有一个首地址,如 i[0] 代表 &i[0][0] 的地址,i[1] 代表 i[0][0] 的地址。因此,二维数组也可以看作是 m 个长度为 n 的一维数组,引用二维数组需要将每行的首地址赋给指针变量。如下例,用指针修改二维数组内的元素。

#include <stdio.h>
#define M 2 // 定义常量 M,用作二维数组的行数
#define N 4 // 定义常量 N,用作二维数组的列数 int main
{
int a[M][N], *pa;
int i, j;
pa = a[0]; // 将指针变量 *pa 指向数组第 1 行的首地址
printf("请输入数组的数值:");
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
scanf("%d", pa + i * N + j); // 从键盘输入获取数据,保存到数组中
putchar('\0'); // 换行
}
} printf("数组内的数值是:");
for (i = 0; i < M * N; i++)
{
printf("%d\n", *(pa + i)); // 输出数组的值
} return 0;
}

该代码首先将数组 a 的第一行首地址赋值给整型指针变量。第一组循环使用数组行和列的关系计算数组元素内存中的位置,给数组 a 的每个元素赋值。第二组循环通过指针变量 pa 间接引用数组 a 内的元素,将所有数组元素的数组输出。

4.6.3 指针 与 字符串数组

字符型指针变量指向字符串数组首地址后,该指针即可当作字符串使用。字符串处理函数通常根据字符串结束符判断该字符串的长度,所以这些函数都会延字符串首地址向后遍历,直到找到字符串结束符。下列用于简单的字符串输入与输出。

char c[20], *pc;		// 定义字符型数组 c 与 字符型指针变量 pc
pc = c; // 字符型数组 c 的首地址赋给指针变量 pc
scanf("%19s", pc); // 通过 pc 间接引用数组 c,为数组 c 初始化
puts(pc); // 输出 pc 所指向的字符串

puts() 函数的作用是将字符串无格式输出,当 *pc 作为其参数时,会内存中将 *pc 所指向的地址开始,到字符串结束符之间的字符输出到终端。假如输入的字符串为“I love China!”,将代码最后一行改为:

puts(pc + 2);		// 输出内存中从 pc + 2 开始,到字符串结束符为止的字符串

那么,该程序的输出为 “love China”,因为 puts()函数会跳过字符串数组的前 2 个字符开始处理。如果字符数组中没有字符串结束符,则调用 printf() 或 puts() 输出函数后程序会出错(一直向后处理,输出很多意向不到的字符,直到遇到值为 0 的内存块)。如果字符型指针变量没有初始化,如下例所示:

char *pc;			// 字符型数组 c 的首地址赋值给指针变量 pc
scanf("%s", pc); // 通过 pc 间接引用数组 c,为数组 c 初始化

这是一种非常危险的用法,因为 pc 的值不可知,pc 可能指向内存中的任意位置。将字符串保存到 pc 所指向的内存单元中,可能造成严重的系统错误。这种用法称之为无源指针,在程序中应避免出现。

【C语言入门教程】4.6 指针 和 数组的更多相关文章

  1. 【C语言入门教程】4.1 一维数组

    数组与指针涉及到数据在内存中的存储位置问题,数组由连续的存储单元组成,最低地址对应于数组的第一个单元,最高地址对应于数组的最后一个单元.指针是一种特殊的变量,该变量所存放的是内存地址,通过指针变量可访 ...

  2. 《Ruby语言入门教程v1.0》学习笔记-01

    <Ruby语言入门教程v1.0> 编著:张开川 邮箱:kaichuan_zhang@126.com 想要学习ruby是因为公司的自动化测试使用到了ruby语言,但是公司关于ruby只给了一 ...

  3. C语言入门教程-(5)格式化输入输出

    1.输入和输出 在程序的使用中,我们经常可以看的这么一个场景:用户需要输入数据,经过程序运算,得到结果后输出.在C语言中,输入数据和输出数据都是由库函数完成的,通过语句来输入/输出. 2.格式化输出— ...

  4. Go语言入门教程(十)之函数

    Hello 各位小伙伴大家好,我是小栈君,假期一眨眼就过去了.不知道大家玩的是否开心呢? 上次我们讲到了关于Go语言的流程控制,小栈君也希望小伙伴跟着小栈君一步一个脚印的敲一下代码,相互进步.本期我们 ...

  5. c语言该怎么入门?C语言入门教程(非常详细)

    C语言是一门面向过程的编译型语言,它的运行速度极快,仅次于汇编语言.C语言是计算机产业的核心语言,操作系统.硬件驱动.关键组件.数据库等都离不开C语言:不学习C语言,就不能了解计算机底层. 这套「C语 ...

  6. 《JavaScript语言入门教程》记录整理:入门和数据类型

    目录 入门篇 js介绍 历史 基本语法 数据类型 概述 null 和 undefined 数值 字符串 对象 函数 数组 本系列基于阮一峰老师的<JavaScrip语言入门教程>或< ...

  7. 《JavaScript语言入门教程》记录整理:运算符、语法和标准库

    目录 运算符 算数运算符 比较运算符 布尔运算符 二进制位运算符 void和逗号运算符 运算顺序 语法 数据类型的转换 错误处理机制 编程风格 console对象和控制台 标准库 Object对象 属 ...

  8. 《JavaScript语言入门教程》记录整理:面向对象

    目录 面向对象编程 实例对象与 new 命令 this关键字 对象的继承 Object对象的方法 严格模式(strict mode) 本系列基于阮一峰老师的<JavaScrip语言入门教程> ...

  9. Go 语言入门教程,共32讲,6小时(已完结)

    Go语言入门教程,共32讲,6小时(完结) 在B站:https://www.bilibili.com/video/BV1fD4y1m7TD/

  10. 【C语言入门教程】7.3 结构体指针的定义和引用

    C 语言中指针的操作非常灵活,它也能指向结构体变量对结构体变量进行操作.在学习结构指针之前,需要再次加深对指针的认识.声明指针变量时所使用的数据类型修饰符实际上的作用是定义指针访问内存的范围,如果指针 ...

随机推荐

  1. python中%和format

    两者都是格式化字符串用的,前者是比较老的版本,现在已经不推荐,后者更强大一些 % In [22]: print '%s' % 'hello world' hello world In [23]: pr ...

  2. 个人作业—Week3

    博客阅读体会 阅读了十几位软件工程师前辈的博文,了解了前辈们作为一名软件工程师的成长经历,我有一些感触. 这十几位前辈们的经历有着很大的差别,有的科班出身,有的则完全自学成才.不同的经历使得前辈们看问 ...

  3. Linux DHCP通过OPTION43为H3C的AP下发AC地址

    对于DHCP服务,可以在很多平台上进行设置.那么这里我们就主要讲解一下在Linux DHCP服务器上通过option 43实现H3C的AP自动联系AC注册的相关内容.原来的DHCP Server是放在 ...

  4. 初识JSLint及建议JS编码风格

    可能都或多或少的知道JSLint是一个JavaScript的代码质量工具,一个JavaScript语法检查器和校验器,它能分析JavaScript问题并报告它包含的缺点. 被发现的问题往往是语法错误, ...

  5. 循序渐进 Jprofiler

    一 Jprofiler 1 什么是Jprofiler JProfiler是一个全功能的Java剖析工具(profiler),专用于分析J2SE和J2EE应用程式.它把CPU.线程和内存的剖析组合在一个 ...

  6. iOS - CAEmitterLayer流星

    效果图: 流星: #pragma mark - loading animation - (void)showLoadingAnimation { CGRect mainBounds = [[UIScr ...

  7. [USACO 2010 OPEN]SLIED

    传送门 这道题的题意描述简直有毒.题没看完一眼分层图,然后火速敲了个堆优化的dijkstra,然后就被样例教做人了QAQ 这里说的最坏的情况让我很迷茫?感觉很难判定到底什么是最坏的情况以及确定了最坏的 ...

  8. 高可用与负载均衡(1)之linux系统的数据链路层负载均衡

    preface 在蓝厂就职到时候,每台缓存服务器都能够跑到2G的流量,这么大的流量,有人会问,服务器是不是安装的万兆网卡,no no no,仅仅是3张千兆网卡绑定在一块.万兆网卡的服务器少见,大多数都 ...

  9. webservice理解

    什么是webservice? 1.基于web的一种服务,webservice分为服务器端server和客户端client. server端会会提供一些资源供客户端的应用来访问(获取所需要的数据) 2. ...

  10. js005-引用类型

    js005-引用类型 数据类型分为基本类型和引用类型:基本类型值如下:Undefined.Null.Bollean.Number.String 本章内容: 1.使用对象 2.创建并操作数组 3.理解基 ...