数组和指针

数组和指针

下面复习一下什么是数组,什么是指针:

●       数组是相同类型的对象集合,可以用一个名称引用。例如,数组scores[50]可以含有50场篮球季赛的比分。使用不同的索引值可以引用数组中的每个元素。scores[0]是第一个分数,scores[49]是最后一个分数。如果每个月有10场比赛,就可以使用多维数组scores[12][10]。如果一月开始比赛,则五月的第3场比赛用scores[5][2]引用。

●       指针是一个变量,它的值是给定类型的另一个变量或常量的地址。使用指针可以在不同的时间访问不同的变量,只要它们的类型相同即可。

数组和指针似乎完全不同,但它们有非常密切的关系,有时还可以互换。下面考虑字符串。字符串是char类型的数组。如果用scanf()输入一个字符,可以使用如下语句:

char  single;

scanf("%c", &single);

这里,scanf()需要寻址运算符,因为scanf()需要存储输入数据的地址。然而,如果读入字符串,可以编写如下代码:

char  multiple[10];

scanf("%s",  multiple);

这里不需要使用&运算符,而使用了数组名称,就像指针一样。如果以这种方式使用数组名称,而没有带索引值,它就引用数组的第一个元素的地址。

但数组不是指针,它们有一个重要区别:可以改变指针包含的地址,但不能改变数组名称引用的地址。

下面通过几个例子来了解数组和指针如何一起使用。这些例子串在一起,构成一个完整的练习。通过这些练习,很容易掌握指针的基本概念及其和数组的关系。

试试看:数组和指针

这个例子进一步说明了,数组名称本身引用了一个地址,执行以下程序:

/* Program 7.4 Arrays and pointers - A simple program*/

#include <stdio.h>

int main(void)

{

char multiple[] = "My string";

char *p = &multiple[0];

printf("/nThe address of the first array element : %p", p);

p = multiple;

printf("/nThe address obtained from the array name: %p/n", p);

return 0;

}

在某台计算机上的输出如下所示:

The address of the first array element : 0x0013ff62

The address obtained from the array name: 0x0013ff62

代码的说明

可以从这个程序的输出中得到一个结论:&multiple[0]会产生和multiple表达式相同的值。这正是我们期望的,因为multiple等于数组第一个字节的地址,&multiple[0]等于数组第一个元素的第一个字节,如果它们不同,才令人惊讶。如果p设置为multiple,而multiple的值与&multiple[0]相同,那么p+1等于什么。试试下面的例子。

试试看:数组和指针(续)

这个程序说明了将一个整数值加到指针上的结果:

/* Program 7.5 Arrays and pointers taken further */

#include <stdio.h>

int main(void)

{

char multiple[] = "a string";

char *p = multiple;

for(int i = 0 ; i<strlen(multiple) ; i++)

printf("/nmultiple[%d] = %c *(p+%d) = %c &multiple[%d] = %p p+%d = %p",

i, multiple[i], i, *(p+i), i, &multiple[i], i, p+i);

return 0;

}

输出如下:

multiple[0] = a *(p+0) = a &multiple[0] = 0x0013ff63 p+0 = 0x0013ff63

multiple[1] =    *(p+1) = &multiple[1] = 0x0013ff64 p+1 = 0x0013ff64

multiple[2] = s *(p+2) = s &multiple[2] = 0x0013ff65 p+2 = 0x0013ff65

multiple[3] = t *(p+3) = t &multiple[3] = 0x0013ff66 p+3 = 0x0013ff66

multiple[4] = r *(p+4) = r &multiple[4] = 0x0013ff67 p+4 = 0x0013ff67

multiple[5] = i *(p+5) = i &multiple[5] = 0x0013ff68 p+5 = 0x0013ff68

multiple[6] = n *(p+6) = n &multiple[6] = 0x0013ff69 p+6 = 0x0013ff69

multiple[7] = g *(p+7) = g &multiple[7] = 0x0013ff6a p+7 = 0x0013ff6a

代码的说明

注意输出中右边的地址列表。p设置为multiple的地址,p+n就等于multiple+n,所以multiple[n]与*(multiple+n)是相同的。地址加上了1,对于元素占用一个字节的数组来说,这正是我们期望的。从输出的两列中可以看出,*(p+n)是给p中的地址加上整数n,再对得到的地址取消引用,就计算出了与multiple[n]相同的结果。

试试看:不同类型的数组

这很有趣,计算机可以将多个数字加在一起。下面改变数组的类型,看看会发生什么:

/* Program 7.6 Different types of arrays */

#include <stdio.h>

int main(void)

{

long multiple[] = {15L, 25L, 35L, 45L};

long * p = multiple;

for(int i = 0 ; i<sizeof(multiple)/sizeof(multiple[0]) ; i++)

printf("/naddress p+%d (&multiple[%d]): %d *(p+%d) value: %d",

i, i, p+i, i, *(p+i));

printf("/n Type long occupies: %d bytes/n", sizeof(long));

return 0;

}

编译并执行这个程序,得到完全不同的结果:

address p+0 (&multiple[0]): 1310552 *(p+0) value: 15

address p+1 (&multiple[1]): 1310556 *(p+1) value: 25

address p+2 (&multiple[2]): 1310560 *(p+2) value: 35

address p+3 (&multiple[3]): 1310564 *(p+3) value: 45

Type long occupies: 4 bytes

代码的说明

这里将printf()函数的第二个参数及后面的参数用空格分隔开,以便于看出格式指定符和参数之间的对应关系。这次,指针p设置为multiple的地址,而multiple是long类型的数组。该指针最初包含数组中第一个字节的地址,也就是元素multiple[0]的第一个字节。地址用指定符%d显示,所以它们都是十进制值,这将易于看出后续地址的区别。

注意看输出。在这个例子中,p是1 310 552 ,p+1是1 310 556 ,而1 310 556 比1 310 552 大4,但我们仅给p加上了1。这并没有错。编译器知道,给地址值加1时,就表示要访问该类型的下一个变量。这就是为什么声明一个指针时,必须指定该指针指向的变量类型。char类型存储在一个字节中,long变量一般占用4个字节。在计算机上声明为long的变量占4个字节,给long类型的指针加1,结果是给地址加4,因为long类型值占4个字节。如果计算机在8个字节中存储long类型,则给指向long的指针加1,会给地址值加8。

注意,这个例子可以直接使用数组名称。编写for循环,如下所示:

for(int i = 0 ; i<sizeof(multiple)/sizeof(multiple[0]) ; i++)

printf(

"/naddress multiple+%d (&multiple[%d]): %d *(multiple+%d) value: %d",

i, i, multiple+i, i, *(multiple+i));

这个循环可以执行,因为表达式multiple和multiple+i都等于一个地址。我们输出这些地址的值,再使用*运算符输出这些地址存储的值。地址的算术运算规则与指针p相同。给multiple加1,会得到数组中下一个元素的地址,即内存中multiple后面的4个字节。但注意,数组名称是一个固定的地址,而不是一个指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值