C语言基本功修炼秘籍第5节,初学者福音,几个C语言指针的问题详解

鉴于很多C语言初学者都觉得指针非常难,本文将初学者常常觉得迷惑的地方以问答的形式解答,希望能够对读者有所帮助。

小明定义了一个C语言函数 int f(int * ),为什么 f(&5) 不能正常工作呢?

如果希望传递 5 给函数 f(),在C99中,可以使用下面这种方法:

f( (int[]){5} );

上面这行C语言代码相当于定义了一个数组,并且数组只有一个元素 5,函数 f() 接收到的参数是该数组,只不过这一过程中的数组名没有“显示”。

抛开C99的这个特性,C语言调用 f(&5) 就不能这么写了,而是需要借助变量:

int five = 5;
f(&five);

在C语言中,接受某个值指针的函数是有可能通过该指针修改该值的(即使程序员无此打算,C语言还是会一直这么认为),因此只有变量才能胜任。在C语言中,常数是只读的,只能作为右值,& 运算符是不能处理常数 5 的,f(&five) 会引发编译错误。

表达式 * p++ 增加了 p 指向的数值,还是指针 p 本身?

C语言中的 ++ 和 -- 运算符的优先级高于 * 运算符,所以 *p++ 其实就相当于 *(p++)。显然,++ 运算符增加的是指针 p 本身的值,不过在指针 p 自增之前,*p++会先返回 p 指向的值。如果希望 ++ 运算符增加 p 指向的值,应该使用括号运算符:(*p)++

小明想使用指针操作数组里的数值,下面这段C语言代码有什么问题?

小明预计程序会输出 3,但是程序却输出了“垃圾值”,他的C语言代码如下,请看:

int array[5], i, *ip;

for(i = 0; i < 5; i++)
    array[i] = i;
ip = array;

printf("%d\n", *(ip + 3 * sizeof(int)));

为什么上述C语言程序没有按照小明的预期输出?

小明是“聪明反被聪明误”了,他发现数组 array 是 int 型的,所以在指针加数上乘上了 sizeof(int)。其实,C语言中的指针加法运算会自动考虑元素类型的,所以小明应该修改 printf() 语句的代码:

printf("%d\n", *(ip + 3));

这样他的C语言程序就会输出数组 array 的第 3 个元素了。事实上,使用指针 ip 访问数组 array 中的元素时,也可以以“数组的形式”进行,例如:

printf("%d\n", ip[3]);

这样也就清楚了,小明原本的写法相当于 ip[3*sizeof(int)],如果 int 类型占用 4 个字节,其实也就是访问了 array[12],这超出了数组范围,程序的输出自然就不可预知了。

小明使用 char * 指针指向 int 型数组,为什么下面这行C语言代码就不正常了呢?

小明的C语言代码是下面这样的,他发现这段代码甚至都不能编译通过,为什么呢?

int main()
{
    int arr[] = {1, 2, 3, 4, 5};

    char *p = (char *)arr;
    ((int*)p)++;

    return 0;
}


这是因为在C语言中,强制类型转换运算并不意味着“忽略类型差异,强制按照指定类型执行”。按照C语言标准,强制类型转换将产生一个右值,而 ++ 运算符只能操作左值(lvalue),因此标准C语言编译器当然会报错了。例如使用gcc编译器编译上述C语言代码,将得到如下错误:

可能有部分C语言编译器可能做了非标准扩展,能够编译上述代码。

小明写出((int*)p)++;的本意应该是希望产生下面这样的C语言代码:

p = (char *)((int *)p + 1);

或者以更简单的形式:

p += sizeof(int);

再或者,也可以多写一行C语言代码:

int *ip = (int *)p;
p = (char *)(ip + 1);

虽然有多种方法可以实现小明的想法,但是仍然应该尽量避免使用不恰当类型的指针操作数据。

小结

C语言的大多语法都是简单易懂的,这常常会给初学者一种“别人都说C语言难,我看也不过如此”的感觉。但是这种感觉常常会停止在初学者学到指针时,这是一些读者跟我说的。为此,本节讨论了几个比较典型的初学者会遇到的问题,并做了较为详细的解析。

本专栏是C语言基本功修炼秘籍,对指针的剖析自然是少不了的,接下来几节,将更加深入的探讨指针的用法,敬请关注。

阅读更多:   C语言
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif