您的位置:首页 > 其它

关于数组和指针(引用《C和指针》上的一段内容)

2013-07-24 11:05 323 查看
牢牢记住下面几个常用的字符串函数,它们只能用来操作以byte为单位元素的字符,不可以用于int型等其它类型:

size_t strlen(const char *s);

char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);

int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);

char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);

char *strerror(int errnum);

char *strstr(const char *haystack, const char *needle);
char *strcasestr(const char *haystack, const char *needle);

char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);


指针和数组并不是相等的,为了说明这个概念,考虑以下两个声明,

int a[5];

int *p;

声明一个数组时,编译器将根据声明所指定的元素数量为数组保留内存空间,然后再创建数组名,它的值是一个常量,指向这段内存空间的起始位置。声明一个指针变量时,编译器只为指针本身保留内存空间,它并不为任何整型值分配内存空间。而且,指针变量并未被初始化为指向任何现有的内存空间,如果它是一个自动变量,它甚至根本不会被初始化。把这两个声明用图的方法来表示,就可一发现他们之间存在显著不同。

因此,上述声明之后,表达式*a是完全合法的,但表达式*b是非法的。*b将访问内存中某个不确定的位置,或者导致程序终止,另一方面,表达式b++可以通过编译,但a++却不行,因为a的值是个常量。

数组名做形参时,为什么可以更改指针的值呢,比如下面的函数原型

void work(int *array)

既然array指向数组,那么为什么在函数体中,可以对array做加减操作呢。这是因为不管是传值还是传指针,在形参的地方都会生成一个临时变量接受传来参数的值,那么在传指针的时候,实际上是定义了一个形式参数接受原参数的值,和原指针指向同一个地方。原来参数是数组名,但是形式参数是又重新定义的变量,它和数组名指向同一个地方,变量的值是可变的,因此可以对array做加减操作,而不会影响原来数组名指针。从这层意义来说,实际上只有一种传递参数的方式,就是传值!!!

上面的形参还有另外一种形式

void work(int array[])


在传递数组名的时候,两者是等效的,但是仅限在传递数组名的上下文环境中,实际上,我们更应该使用第一种指针的形式,因为实参实际上是个指针,而不是数组!!!

现在应该清楚为什么函数原型中的一维数组形参无需写明它的元素数目,因为函数并不为数组参数分配内存空间。形参只是一个指针,它指向的是已经在其他地方分配好内存的空间。这个事实解释了为什么数组形参可以与任何长度的数组匹配,它实际传递的只是指向数组第一个元素的指针,另一方面,这种实现方法无法知道数组的长度。如果函数需要知道数组的长度,它必须作为一个显式的参数传递给函数。

作为函数参数的多维数组

作为函数参数的多维数组名的传递方式和一维数组名相同,实际传递的是个指向数组第一个元素的指针。但是两者的区别在于,多维数组的每个元素本身是另外一个数组,编译器需要知道它的维数,以便为函数形参的下标表达式进行求值。现在,让我们来观察一个矩阵:

int matrix[3][10]


我们在想函数传递数组名参数的时候,可以用以下两种方法

void func(int (*mat)[10])
void func(int mat[][10])
在这个函数中,mat的第一个下标根据包含10个元素的整形数组的长度进行调整,接着第二个下标根据整形的长度进行调整。

这里的关键在于编译器必须知道第二个及以后各维的长度才能对各下标进行求值,因此在原型中必须声明这些维的长度。第一维的长度并不需要,因为在计算下标值时用不到。

在编写一维数组形参的函数原型时,你既可以把它写成数组的形式,也可以把它写成指针的形式。但是,对于多维数组,只有第一维可以进行如此选择。尤其是,把func写成下面这样的原型是不正确的:

void func(**mat)

这个例子把mat声明为一个指向整形指针的指针,它和指向整形数组的指针并不是一回事!!!

实际上只需要记住一点:二维数组名是指向数组的指针!!!

C语言的下标访问和用指针访问是一样的!!!

正因为如此,如果定义一个数组array,并且定义两个指针分别指向数组第一个元素和第六个元素。

int array[10];
int *p=array;
int *q=array+5;
我们可以用array[0]访问第一个元素,也可一用p[0]访问,因为p[0]与*(p+0)相同,与array[0]等效。
同理我们也可以有q[3],q[3]解释为*(q+3),即访问第九个元素,既然这样,我们还可以在方括号中放入负值,q[-2]与*(q-2)等效,即访问第四个元素。下标到指针的转换是自动进行的,直接用指针可以省去转换的步骤,提高效率!!!

同一个数组中的两个指针相减,得到的是两个指针之间元素的个数!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: