今天看书的时候遇到了一个问题,觉得有必要记录和总结一下。问题来自书上的一个程序,我把代码简化了一下如下:

   #define MAXLINES 100

   char *lineptr[MAXLINES];

   void writeline(char *lineptr[], int nlines);

   其中writeline函数的定义如下:

   void writeline(char *lineptr[], int nlines)

   {

        while(nlines-- > 0)

             printf("%s\n", *lineptr++);

   }

   我当时疑惑的就是lineptr是一个数组名,可以看做是一个常量指针,可是这里却有lineptr++。如果按照我的理解,代码肯定是错的,可是程序是可以运行的,而且结果正确,所以肯定是我的理解错了。于是我自己编了一个程序,代码如下:

   int main()

   {

       char *s[] = {"12345", "abcde"};

       int i;

       for(i = 0; i != 2; i++)

           printf("%s\n", *s++);

       return 0;

    }

   编译器提示错误:'++' needs l-value,自增运算符需要左值才能用。说明这里的 s 是一个常量指针了。觉得很奇怪,于是对比两个程序发现上面的lineptr是通过一个函数的参数传递过来的,觉得问题可能出现在这里。于是找书认真看了看,发现了这其实是一个关于数组作为函数参数的问题。

   《C和指针》上有较为详细的讲解这个问题。

   书上说,想把一个数组名参数传递给函数,正确的声明方式有两种,就拿第一个程序的函数声明为例:

    1)void writeline(char *lineptr[], int nlines);

    2) void writeline(char **lineptr, int nlines);

   第一个程序中的lineptr是一个指针数组的数组名,普通数组的数组名也可以用上述方式声明。

   这两种声明方式暗示了指针和数组实际是相等的,但是这两个声明相等,只是在当前的这个上下文环境中,如果出现在别处了,就可能完全不同。

   现在可以解决上面的问题了,如果是第二种声明方式,我们能很好的理解为何可以lineptr++,如果是用第一中声明方式,

即函数声明的参数是一个数组,其实在函数体内操作的时候,也是将其当作指针来处理,不是作为常量指针来处理。

   同时我们也可以知道为什么函数原型中的一维数组形参无需写明它的元素个数,因为函数并不为数组参数分配内存空间,形参只是一个指针,它指向的是已经在其他地方分配好的内存空间,它实际上传递的只是指向数组第一个元素的指针。

   在C语言中,什么时候指针和数组名等价,什么时候不等价是我们需要重点研究的问题,不过这会放在以后来讨论。

   今天的问题虽然不复杂,但是还是说明了自己对一些细节不是很了解,不过吃一堑长一智,相信以后碰到类似的代码不会像今天一样疑惑了。