首页 > 试题广场 >

以下程序执行后的输出结果为()

[单选题]
#include <stdio.h>
void func(char *p) { p = p + 1; }
int main() {
    char s[] = {'1', '2', '3', '4'};
    func(s);
    printf("%c", *s);
    return 0;
}
以下程序执行后的输出结果为()
  • 2
  • 编译错误
  • 1
  • 无法确定
p是一个指针,s也是一个指针,指针传指针,还是相当于值传递,函数调用时将s的内容(即字符'1'的地址)拷贝给p,p+1不会对s产生任何影响。想要达到改变s的目的,需要用到指针的指针,代码得这样写:
#include<stdio.h>

void func(char **p)
{
*p=*p+1;
}
int main()
{
char s[]={'1','2','3','4'};
func(&s);
printf("%c",*s);   //此时输出2
return 0;
}
还有一点要说的是,题目代码的第9行应该是printf("%c",*s);,否则,按题目的写法,答案将是无法确定。


        以上内容编辑于  2016-04-20 16:24:31 ,此后,几位读者提出了各种质疑。首先,对于大家真诚的指教,在下表示衷心的感谢!看了大家的质疑,在下又认真看了这道题,发现,在下之前的解释,确实有错误的地方!在这里,在下向所有读者道歉,对不起,误导大家了!请大家原谅!
        本着将功补过的心态,在下再重新解释一下这道题,也顺便介绍一下C语言中数组和指针的相关知识。
       在下才疏学浅,再次解释中错误疏漏之处依然在所难免,再次恳请大家批评指正!

1.再论原题
       我们知道,s中存储的值是一个地址,即数组首元素'1'所在存储单元的地址,执行func函数时,将这个地址值传给p,然后,在函数体中,对p执行加1操作,使p指向数组的第1个元素(从0算起),即s[1]。但是,这只是对p的修改,跟s毫无关系!在传参时,将s的值拷贝给p,之后,s与p就毫无关系了。 func函数结束后,p超出作用域被释放掉了,此时打印s指向的内容(即*s),仍然是s[0]的值,而不是s[1]的值。所以,原题应该选择C。
        到这里,其实题目本身已经解决了。在下下面讲到的,是由这道题引出的更加深入的知识。
2.s与&s
大家先看下面的代码:

下面是运行结果:

(注:以上是VS2015上的测试结果,在其它IDE上,结果是一样的)
        相信大家和我一样惊讶,&s不是对s取地址吗,怎么&s和s的值是一样的呢?
        在C语言中,许多连续内存都是用“起始地址+偏移量”的形式表示的,数组就是如此。对char *s[]={'1','2','3','4'}而言,s就是首地址,所以s本身是char*类型的。
        再说&s,此时,&运算符并不会取s得地址,而是从“会意”的角度,对s做一种“向上转换”。原来s是char*类型的,指向数组的首元素,现在&s"向上转换",使得&s指向了整个数组,所以,&s的类型是char(*)[4]。char(*)[4]的意思是:这是一个指针,该指针指向一个有4个char型元素的数组。&s指向整个数组,数组往往有不止一个元素,但&s只能是一个值,那么,这个值该怎么设置呢?C语言将其设置为数组首元素的地址。没错,如果s是一个一维数组的名称的话,s与&s的值是相同的,只不过两者所表示的意义不同,前者表示数组的首元素,后者表示整个数组
3.在下的错误
       正是因为&s的值也是数组首元素的地址,所以func(&s)传参后,p的值也是数组首元素的地址,于是*p的值就是数组首元素的值,执行*p=*p+1就是对数组首元素加1,上面的运行结果也说明了这一点。在  2016-04-20 16:24:31 的解释中,由于在下以为&s得到的是s的地址,于是也就认为*p=*p+1是修改了s的值,现在看来,这是完全错误的。巧合的是,正是由于s[1]=s[0]+1,才使得在下当时没有立即发现错误。
4.编译通不通过的问题
        请广大读者注意,题目给的是C代码,所以,我们不要试图把它作为.cpp文件去编译!
        在前面的“2.s与&s”中说过,&s是char(*)[4]类型的。C编译器要求比较松,允许char(*)[4]向char**转换,只不过会给出警告;而C++编译器要求比较严苛,它不允许char(*)[4]向char**转换。
下面是在下2016-04-20 16:24:31 提供的代码作为.c文件在VS2015上编译时给出的警告:
 warning C4047: “函数”:“char **”与“char (*)[4]”的间接级别不同
下面是在下2016-04-20 16:24:31 提供的代码作为.cpp文件在VS2015上编译时给出的错误提示:
错误C2664“void func(char **)”: 无法将参数 1 从“char (*)[4]”转换为“char **”

       好了,该解释的都解释了,对于在下先前所犯的错误给官大读者带来的误导,在下再次表示深深的歉意,万望大家谅解!再次感谢广大读者的批评指正!
编辑于 2016-09-16 20:09:50 回复(15)
改变变量的值,要用指针。
改变指针的值,要用指针的指针。
发表于 2016-07-04 09:23:24 回复(1)
首先,分配一块地址给char[]={'1','2','3','4'},s指向这块地址,且是第一个元素'1',函数调用使得p也指向这块地址,且指向第一个元素'1',自此p和s再无联系,但不管谁改变了地址块内容,*指针取相同地址处值相同。 若*p=*p+1,则p会改变第一个元素值,*p=2,*s=2,且都指向第一个元素.数组变为 char[]={'2','2','3','4'} 若 p=p+1,会使p指向第二个元素'2',s还是指向第一个元素'1',*p=2,*s=1,数组变为char[]={'1','2','3','4'} 也就是说p通过*p+N改变了地址块内数组的值,*s值会变,但p通过p=p+N改变了本身的值,只会改变p的指向,不会改变s及*s的值。
编辑于 2018-05-28 03:50:12 回复(2)
选D吧,s是一个地址啊,要打印出1的话应该是printf(“%c”,*s);
发表于 2016-04-10 22:07:45 回复(0)

这道题有个陷阱,初一看形参是个指针,潜意识就会觉得地址传递,形参能改变实参,但是实参也是一个指针变量,所以实际上还是值传递,形参在栈里新开辟了一个字节的空间,存放了数组的首地址。外部函数里面虽然指向了第二个元素,但是没有改变实参

发表于 2018-12-12 19:38:34 回复(0)
http://www.cnblogs.com/lipeil/archive/2012/10/26/2740729.html 指针作为参数传递给函数,实际上是值传递。 而在题目的函数中,做的是p的地址的变化,这个拷贝s而得来的p指针不会改变s指针所指向的地址。因此s仍然指向数组的首位。只有当用*p改变变量值的时候,*s的取值才会变,但s指向的地址不会受其影响。 终结:当离开函数后,指针本身的地址,指针所指向内存的地址一定不会改变,只有指针所指向内存地址的变量中的值可能改变。
发表于 2016-11-16 18:20:20 回复(0)
经过函数调用后,只是改变了形式参数指针p的指向,p指向了第二个字符,而实际参数s仍然指向第一个字符,所以答案为 '1'。
发表于 2022-03-21 11:08:11 回复(0)
voidfunc(char*p)
{
    p=p+1;
}

这个函数依旧是值传递,不会影响实参,只是将p的值初始化为s的地址值,p不等于s
发表于 2020-06-18 14:46:24 回复(0)
#include<iostream>
#include<string>
#include<algorithm>
using namespace::std;
//二级指针 
void func(char **p)
{
*p = *p + 1;
}
int main()
{
char s[] = { '1', '2', '3', '4' };
char *q=s;
func(&q);
printf("%c", *q); //output 2
return 0;
}
//一级指针
void func(char *p)
{
p = p + 1;
}
int main()
{
char s[] = { '1', '2', '3', '4' };
char *p = s;
func(p);  //指针传指针是值传递。实参不变
printf("%c", *p); //output 1
return 0;
}
发表于 2017-06-30 18:11:02 回复(0)
一个图说明问题:
发表于 2016-04-13 21:57:52 回复(2)
进入被调函数之后,产生一个临时的指针,指向数组第一个元素,然后在被调函数内改变了这个临时指针的指向,等被调函数执行完之后,这个指针就不再存在了,这整个过程,数组首元素地址s一直没有变。要想改变指针的值,就要传入二级指针。
编辑于 2020-03-10 17:50:31 回复(0)
p是一个指针,s也是一个指针,指针传指针,还是相当于值传递
发表于 2019-03-13 16:47:45 回复(0)


运行结果:

理解:
虽然函数的参数传的是指针,可是这里却相当于是值传递,对形参的改变是不会影响实参的值的改变的,所以s 还是取到的是第一个元素的值
所以结果为1

发表于 2017-08-11 14:33:41 回复(0)
void func(char *p)
{
    *p=*p+1;
    p++;
}
改为这样既可。原题中的p=p+1只是将指针移到下一位而已,并没有改变内存中的值。
发表于 2017-07-23 16:12:31 回复(0)
函数的操作对数组没有任何影响,用%c打印*s只能打印s指向的第一个字符,即s[0].
发表于 2016-08-09 10:03:45 回复(0)
选B,编译出错。
如果把printf(“%c”,s); 改为printf(“%c”,*s); 则选择C
如果想要func函数达到修改指针索引的目的,则需要引入二级指针。
void func(char **p){
    *p = *p+1;
}

int main(int argc,char ** argv){

    char s[]={'1','2','3','4'};
    char *tmp = s; 
    func(&tmp);//注意上述转换,如果直接调用fun(&s),会出现编译错误cannot convert ‘char (*)[4]’ to ‘char**’ 
    printf("%c\n",*tmp);
    return 0;
}

发表于 2016-05-03 16:36:23 回复(0)
fyf头像 fyf
在执行   func(s)时,实际上是这样的过程
func(int *p = s){}
发表于 2016-04-23 20:15:24 回复(0)
答案应该为 1 
因为 func 函数并没有改变指针的位置,但是此函数可以改变 指针所指向的值。
发表于 2016-04-08 23:08:37 回复(2)
运行一下,输出的是这个呀~
编辑于 2016-04-14 19:17:50 回复(1)
可以理解为形不改实嘛?

发表于 2024-07-17 11:17:49 回复(0)