Chinaunix首页 | 论坛 | 博客
  • 博客访问: 91712
  • 博文数量: 26
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 291
  • 用 户 组: 普通用户
  • 注册时间: 2014-01-22 16:05
文章分类
文章存档

2014年(26)

分类: C/C++

2014-04-18 09:09:43

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

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

   今天的问题虽然不复杂,但是还是说明了自己对一些细节不是很了解,不过吃一堑长一智,相信以后碰到类似的代码不会像今天一样疑惑了。
阅读(2834) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

CU博客助理2014-05-22 13:16:52

嘉宾点评:
博主很有心,进行了仔细的验证。从教10年,我发现C语言指针问题是我国计算机人民群众心中永远的痛。这与C语言教材有关,从老谭开始到目前林林总总的C课本,几乎所有编者都在回避C指针问题,个人认为原因有二:一是考试不需要彻底搞懂C指针,二是编者也未必搞懂了C指针。所以,一代传一代,真正弄明白的人都是像博主这样一边试一边对照国外的书学过来的,或者毕业后真正从事相关开发的(尤其是嵌入式系统的从业人员)。站在过来人的角度,对博主的疑惑进行一下梳理,希望对你有所帮助:首先不用疑惑,数组名就是地址常量,不能用++,所以main函数中的*s++就是错误的,但是在函数定义时,参数的作用是接收其它传入值,不管这个值是否为指针。当然了,形参可以是变量,或缺省常量,如果是缺省常量,只能定义在参数列表的后面。你这里的定义并非缺省常量,所以该形参是一个变量。这就是为什么说在作为参数时, 数组和指针是等价的,因为发生拷贝出现了值传递,const直接转为了non-const。我写了篇博客详细回答了这个问题,请参看:http://blog.chinaunix.net/uid-22414998-id-4242479.html(感谢您参与“原创博文评选”获奖结果即将公布)