每天记一点:数组和指针(摘自《C和指针》)

来源:互联网 发布:靠谱的淘宝优惠券软件 编辑:程序博客网 时间:2024/04/30 06:43

摘自《C和指针》,觉得写的很好,让我对基础方面理解通了很多。故记录下来。

 

关于数组与指针:

1、数组具有一些和指针完全不同的特性。例如,数组具有确定数量的元素,而指针指示一个标量值。编译器用数组名来记住这些属性。只有数组名在表达式中使用时,编译器才会为它产生一个指针常量。

2、int a[10];   int b[10];  其下面的表达式是错误的:b = a ; 你不能使用赋值符把一个数组的所有元素复制到另一个数组。你必须使用一个循环,每次复制一个元素。可以采用提供的系统函数strcpy(a, b);

3、int  array[10];  int *ap;  解释ap[-1] 

初看一下,会觉得其表达式错误的。但是其是正确的。Ap指向第3个元素(就是下标值为2的元素),所以使用偏移量-1使我们得到它的前一个元素,也就是array[1]

4、考虑下面两个声明:

   int a[5];

   int *b;

   a 和 能够互换使用吗?他们都具有指针值,它们都可以进行间接访问和下标引用操作。但是它们还是存在相当大的区别。

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

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

注意*b 将访问内存中某个不确定的位置。从图上可以发现,b中的值为“?”。其声明int *b 的时候并没有为其指向哪个位置。所以其为问号。所以对于在使用指针的时候内存的分配问题也该需要引起重视。

5、理解函数参数为数组、指针和标量:

   void  function(int  a,  int  *pb,  int  arrc[]);

   先看下面几段文字:

   (1C函数的所有参数均以“传值调用”方式进行传递,这意味着函数将获得参数值的一份拷贝。这样,函数可以放心修改这个拷贝值,而不必担心会修改调用程序时间传递给它的参数。这个行为与ModulaPascal中的值参数相同。

C的规则很简单:所有参数都是传值调用。但是,如果被传递的参数是一个数组名,并且在函数中使用下标引用该函数的参数,那么在函数中对数组元素进行修改实际上修改的是调用程序中的数组元素。函数将访问调用程序的数组元素,数组并不会被复制。这个行为被称为“传址调用”。

数组参数的这种行为似乎与传值调用规则相悖。但是此处其实并无矛盾之处-------数组名的值实际上是一个指针,传递给函数的就是这个指针的一份拷贝。下标引用实际上间接访问的另一种形式,它可以对指针执行间接访问操作,访问指针指向的内存位置。参数(指针)实际上一份拷贝,但在这份拷贝上执行间接访问操作所访问的是原先的数组。

而对于指针其也一样,所有的参数都是通过传值方式传递的。当然,如果你传递了一个指向某个变量的指针,而函数对该指针执行了间接访问操作,那么函数就可以修改那个变量

(我在这三段的理解就一点:函数参数传递的都是标量,如上面函数中的参数a。而对于传递数组,其也是传递了一个标量值,即arrc的首地址。其我们是无法修改这些值并继续返回给调用的函数中的,因为其只是这些数据的一份拷贝。当我们传递一个数组时,修改的是这个数组(即类似于指向这个数组中数据的指针)指向的数据,而其实参并没有改变。这个指针指向的位置不变,但是其里面的数据改变了。也就达到了对数据的修改效果。)

2)在声明数组参数时不指定它的长度是合法的,(即arrc[]没有指定大小)因为函数并不为数组元素分配内存。间接访问操作将访问调用程序中的数组元素。这样,一个单独的函数可以访问任意长度的数组。

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

原创粉丝点击