指针与数组
指针与地址
通常的机器有一系列连续的编号或编址的存储单元,它们可以以连续的方式存放不同数据类型的数据。如4个相邻的字节存放一个long类型变量,单个字节存储char类型变量。
一元运算符&可用于取一个地址。 P = &c; 将c的地址复制给变量P,我们称P为指向c的指针。地址运算符&只能应用于内存中的对象,即变量和数组。 他不能作用于表达式,常量或寄存器变量。 一元运算符*是间接寻址或间接引用的运算符。当它作用于指针时,将访问指针所指向的对象。
int x = 1, y = 2, z[10];
int *ip;
ip = &x;
y = *ip;
*ip = 0;
ip = &z[0];
指针只能指向某种特定类型的变量,每个指针都必须指向某种特定的数据类型。(EXCEPTION:void类型的指针可以存放指向任何数据类型的指针,但是不能间接引用自身。) 一元运算符的*和&的优先级高于算术运算符,*ip += 1等同于 ++*p等同于(*ip)++。
指针和函数
指针参数使得被调用的函数可以访问和修改主调函数中对象的值。除了经典的swap例子外,还有: 函数getline接受自由格式的输入,并且执行转换,输入的字符分解成整数,每次调用获得一个整数。getint需要返回转换后得到的整数,在到达输入结尾时要返回文件结束标记。 scanf的设计方法:将标识是否到达文件结尾状态作为getint的返回值,使用一个指针参数储存转换后的整数并传回主调函数。
int n, array[SIZE], getint(int *);
for (n = 0; n < SIZE && getint(&array[n]) != EOF; n++)
;
此getint函数在到达文件末尾是返回EOF,当下一个输入不是数字时返回0,当输入中包含一个有意义的数字时返回一个正值。
#include <ctype.h>
int getch(void);
void ungetch(int);
int getint(int *pn){
int c, sign;
while (isspace(c = getch()))
;
if(!isdigit(c) && c != EOF && c != '+' && 'c' != '-') {
ungetch(c);
return 0;
}
sign = (c == '-') ? -1 : 1;
if (c == '+' || c == '-')
c = getch();
for (*pn = 0; isdigit(c); c = getch())
*pn = 10 * *pn + (c - '0');
*pn *= sign;
if (c != EOF)
ungetch(c);
return c;
}
*getchar(), getc(), getch(), getche() The difference between getc() and getchar() is getc() can read from any input stream, but getchar() reads from standard input. So getchar() is equivalent to getc(stdin).
getch() is a nonstandard function and is present in conio.h header file which is mostly used by MS-DOS compilers like Turbo C. It is not part of the C standard library or ISO C, nor is it defined by POSIX (Source: http://en.wikipedia.org/wiki/Conio.h) Like above functions, it reads also a single character from keyboard. But it does not use any buffer, so the entered character is immediately returned without waiting for the enter key. getche() like getch(), this is also a non-standard function present in conio.h. It reads a single character from the keyboard and displays immediately on output screen without waiting for enter key.
数组和指针
数组下标能完成的事情都可以通过指针来实现,执行速度也更快。
int *pa, a[10];
pa = &a[0];
*(pa + 1)指向a[1], (pa + i)指向a[i]。然而在计算数组元素a[i]时C语言会先把其转化成(a+i)的形式,然后再进行求值。同理,加上取址运算符,&a[i]和a+i的含义也是相同的。把数组名传递进一个函数时,实际上传递的是该数组的第一个元素的地址。在被调用函数中,该参数是一个局部变量,因此,数组名必须是一个指针,也就是一个存储地址值的变量。 例如,编写strlen函数:
int strlen(*char *s){
int n;
for (n = 0; *s != '\0'; s++)
n++;
return n;
}
在函数定义中,形式参数(formal parameters) char [] 和 char *s 是等价的。我们更习惯于最后一种方式,比前者更直观的表明了参数是一个指针。如果将函数名传递给函数,函数可以根据情况判断是按照数组还是指针处理,随后根据相应方式操作该参数。 也可以把指向子数组的起始位置的指针传递给函数,这样就将数组的一部分传递给了函数。例如,如果a是一个数组,那么下面两个函数调用f(&[2])与f(a+2)都将把起始于2的子数组地址传递给函数f,在函数f中,参数的声明可以是f(array[])e和f(*array)。
|