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

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. xpath中/和//的差别

    xpath中 "/"是在子节点中查找,"//"是在所有子节点中查找,包括子节点的子节点. example: leve1/leve2:得到文本leve2 leve ...

  2. UVa 10720 - Graph Construction(Havel-Hakimi定理)

    题目链接: 传送门 Graph Construction Time Limit: 3000MS     Memory Limit: 65536K Description Graph is a coll ...

  3. web前端开发修炼之道--编写高质量代码

    想想自己的页面实现是否糟糕 Web标准--结构.样式和行为的分离 Web标准可分为三个部分:结构标准.样式标准.行为标准. 结构标准包括XML标准.XHTML标准.HTML标准 样式标准主要是指的CS ...

  4. DNS(二)之构建域名解析缓存

    域名解析缓存的必要性 在部署服务的时候,很多程序需要使用域名解析的功能,一般配置/etc/resovl.conf去指定DNS服务器的IP,但是如果程序发起的请求量较大,那么服务器就容易被DNS服务器禁 ...

  5. JavaWeb---总结(十一)使用Cookie进行会话管理

    一.会话的概念 会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话. 有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学曾 ...

  6. EmguCV 一些基本操作

    http://www.cnblogs.com/alsofly/p/3524866.html?utm_source=tuicool&utm_medium=referral 一.先是在程序中图像的 ...

  7. css012 css布局简介

    css012  css布局简介 一.    网页布局的类型 网页布局的类型 1.固定宽度 2.流式 3.相应式web设计 二.    如何进行css布局 1.强大的<div>标签 网页的h ...

  8. url下载网页的三种方法

    # -*- coding: utf-8 -*- import cookielib import urllib2 url = "http://www.baidu.com" print ...

  9. tomcat的下载安装和配置以及和eclipse的配置

    一.Tomcat的下载安装环境变量配置 下载Tomcat 可以安装Tomcat了.下载好压缩包后,直接解压至某一目录下,目录中不能包含中文,上面安装JDK的时候也是.解压后如下所示: 将此文件夹拷贝到 ...

  10. SVN中Branch和Merge实践

    参考资料:http://blog.csdn.net/eggcalm/article/details/6606520 branch主要用于新功能的开发,开发过程中不断从trunk merge revis ...