关于数组和指针(引用《C和指针》上的一段内容)
2013-07-24 11:05
323 查看
牢牢记住下面几个常用的字符串函数,它们只能用来操作以byte为单位元素的字符,不可以用于int型等其它类型:
指针和数组并不是相等的,为了说明这个概念,考虑以下两个声明,
int a[5];
int *p;
声明一个数组时,编译器将根据声明所指定的元素数量为数组保留内存空间,然后再创建数组名,它的值是一个常量,指向这段内存空间的起始位置。声明一个指针变量时,编译器只为指针本身保留内存空间,它并不为任何整型值分配内存空间。而且,指针变量并未被初始化为指向任何现有的内存空间,如果它是一个自动变量,它甚至根本不会被初始化。把这两个声明用图的方法来表示,就可一发现他们之间存在显著不同。
因此,上述声明之后,表达式*a是完全合法的,但表达式*b是非法的。*b将访问内存中某个不确定的位置,或者导致程序终止,另一方面,表达式b++可以通过编译,但a++却不行,因为a的值是个常量。
数组名做形参时,为什么可以更改指针的值呢,比如下面的函数原型
既然array指向数组,那么为什么在函数体中,可以对array做加减操作呢。这是因为不管是传值还是传指针,在形参的地方都会生成一个临时变量接受传来参数的值,那么在传指针的时候,实际上是定义了一个形式参数接受原参数的值,和原指针指向同一个地方。原来参数是数组名,但是形式参数是又重新定义的变量,它和数组名指向同一个地方,变量的值是可变的,因此可以对array做加减操作,而不会影响原来数组名指针。从这层意义来说,实际上只有一种传递参数的方式,就是传值!!!
上面的形参还有另外一种形式
在传递数组名的时候,两者是等效的,但是仅限在传递数组名的上下文环境中,实际上,我们更应该使用第一种指针的形式,因为实参实际上是个指针,而不是数组!!!
现在应该清楚为什么函数原型中的一维数组形参无需写明它的元素数目,因为函数并不为数组参数分配内存空间。形参只是一个指针,它指向的是已经在其他地方分配好内存的空间。这个事实解释了为什么数组形参可以与任何长度的数组匹配,它实际传递的只是指向数组第一个元素的指针,另一方面,这种实现方法无法知道数组的长度。如果函数需要知道数组的长度,它必须作为一个显式的参数传递给函数。
作为函数参数的多维数组
作为函数参数的多维数组名的传递方式和一维数组名相同,实际传递的是个指向数组第一个元素的指针。但是两者的区别在于,多维数组的每个元素本身是另外一个数组,编译器需要知道它的维数,以便为函数形参的下标表达式进行求值。现在,让我们来观察一个矩阵:
我们在想函数传递数组名参数的时候,可以用以下两种方法
这里的关键在于编译器必须知道第二个及以后各维的长度才能对各下标进行求值,因此在原型中必须声明这些维的长度。第一维的长度并不需要,因为在计算下标值时用不到。
在编写一维数组形参的函数原型时,你既可以把它写成数组的形式,也可以把它写成指针的形式。但是,对于多维数组,只有第一维可以进行如此选择。尤其是,把func写成下面这样的原型是不正确的:
这个例子把mat声明为一个指向整形指针的指针,它和指向整形数组的指针并不是一回事!!!
实际上只需要记住一点:二维数组名是指向数组的指针!!!
C语言的下标访问和用指针访问是一样的!!!
正因为如此,如果定义一个数组array,并且定义两个指针分别指向数组第一个元素和第六个元素。
同理我们也可以有q[3],q[3]解释为*(q+3),即访问第九个元素,既然这样,我们还可以在方括号中放入负值,q[-2]与*(q-2)等效,即访问第四个元素。下标到指针的转换是自动进行的,直接用指针可以省去转换的步骤,提高效率!!!
同一个数组中的两个指针相减,得到的是两个指针之间元素的个数!!!
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)等效,即访问第四个元素。下标到指针的转换是自动进行的,直接用指针可以省去转换的步骤,提高效率!!!
同一个数组中的两个指针相减,得到的是两个指针之间元素的个数!!!
相关文章推荐
- 关于可变数组或字典的拷贝内容的问题(非拷贝指针)
- C/C++中关于地址、指针和引用变量的学习笔记(二) : 数组
- 关于C数组与指针的关系(主要是长度首地址内容)
- C语言关于数组与指针内容小结
- 动态创建二维vector数组 C和C++ 及指针与引用的区别
- 关于理解数组与指针
- C语言中关于字符数组与字符指针的本质区别
- 数组长度为零和空引用的区别 files!=null&files.length()>0 空指针或赋空值
- 关于extern指针和数组的用法
- 数组不是指针——数组地址不能动态分配空间,一个小例子关于指针移动,以及malloc
- 【C/C++】关于引用和指针的问题
- 【错误记录】关于C语言指针和数组
- 指向数组的引用;指向数组的指针;指向类成员的指针;指向类数组成员的指针;二维字符串数组指针
- 关于指向数组的指针
- 关于C语言字符数组、字符串和指针的相关问题
- C语言中关于数组、指针以及函数的一些基本知识
- 关于字符指针和字符数组初始化的问题
- 关于函数指针数组与返回数组指针的函数
- 有一段文本,将文本中的所有单词,存放到一个字符指针数组中(要求每个单词内存恰好)
- 什么是指针?关于指针的数组,数组指针,函数指针,函数指针数组,指向函数指针数组的指针的理解