首页 > 试题广场 >

下面代码不能正确输出hello的选项为

[单选题]
下面代码不能正确输出hello的选项为()
#include<stdio.h>
struct str_t{
   long long len;
   char data[32];
};
struct data1_t{
   long long len;
   int data[2];
};
struct data2_t{
   long long len;
   char *data[1];
};
struct data3_t{
   long long len;
   void *data[];
};
int main(void)
{
   struct str_t str;
   memset((void*)&str,0,sizeof(struct str_t));
   str.len=sizeof(struct str_t)-sizeof(int);
   snprintf(str.data,str.len,"hello");//VS下为_snprintf
   ____________________________________;
   ____________________________________;
   return 0;
}
  • struct data3_t *pData = (struct data3_t*) &str;
    printf("data:%s%s\n", str.data, (char*) (&(pData->data[0])));
  • struct data2_t *pData = (struct data2_t*) &str;
    printf("data:%s%s\n", str.data, (char*) (pData->data[0]));
  • struct data1_t *pData = (struct data1_t*) &str;
    printf("data:%s%s\n", str.data, (char*) (pData->data));
  • struct str_t *pData = (struct str_t*) &str;
    printf("data:%s%s\n", str.data, (char*) (pData->data));
一张图说明问题。

编辑于 2016-05-08 13:14:38 回复(36)
1. 观察结构体空间是否相同
2. 观察data变量的类型
3. 观察输出时强转类型
发表于 2022-05-24 21:06:02 回复(0)
data1_t、 data2_t、 data3_t里都定义了一个数组,数组元素可能是指针可能是正数,是什么不重要,元素的内容不是我们想要的,
我们想要的是首元素的地址,首元素是指针就取指针的地址,是正数就取这个整数的地址。并把这个地址转换为char*型。
发表于 2016-07-09 16:52:15 回复(0)
int main()
{
	char *s[1] = { "dd" };
	cout << *s[0] << endl;
	cout << s[0] << endl;
}
第一个输出 d,
第二个输出 dd,
发表于 2016-07-21 22:17:41 回复(0)
主要是因为C++ 中定义了箭头运算符,箭头运算符把解引用和成员访问两个操作结合在一起,也就是说 it->men (*it).men 表达的含义相同,那么也就是说 pData->data[0]实际上指的是数组首元素而不是地址

发表于 2015-08-15 11:25:56 回复(3)
选项A和B中的pData->data[0]不是数组的地址,而是数组的首元素,相当于是原结构体里面的char,因此必须取地址之后再强制转换成char *类型。 
发表于 2015-08-14 10:50:17 回复(5)
小女子认为,对于B,char *data[1]; data是一个数组,有一个元素,该元素的类型为指针类型,所以data[0]原本就是一个指针,值是一个地址,该地址占据了4个字节,假设data的首地址为8,那么地址8,9,10,11原本都存放着这个地址(这个地址指示的内存单元就存储着对应的字符串),直接输出data[0]相当于输出这个地址指向的字符串(字符串的特殊性质)。后面,这个本来存放地址的地方被hell覆盖了,地址8,9,10,11里存放的不是地址了,而是四个字符hell,如果仍然以地址类型即指针类型去指示data[0]应该获取多少字节的数据,程序就崩了,但是如果是以字符类型去指示获取数据的话,它就会获取一个字节的数据,即字符h,所以说后面的data[0]到底是什么,在于你让它以什么数据类型去获取以它的地址开始的数据。回到原题,(char*)(pData->data[0])其实程序是会崩溃的,因为这句话相当于把 pData->data[0]当做指针类型,那么它会把以 pData->data[0]的地址开始的前四个字节的内容,即 hell(确切的说是这4个字符对应的16进制数)当做是一个地址,但这个地址是无效的,所以程序崩溃了。
编辑于 2015-09-28 20:57:09 回复(7)
太长了,虽然看不懂,但是我会蒙啊
发表于 2019-01-24 21:12:50 回复(0)
个人拙见:本题的关键在于—> 与[]的运算顺序,这两者在一起时,应该是按照从左到右的顺序执行!再结合楼主们的解释,可能会容易理解些。
发表于 2016-11-17 17:14:16 回复(1)
啥头像
这里面的关键是:  “取这个变量的地址”  和  “把变量的值当作地址”  的区别。这题应该  “取变量的地址”
发表于 2015-08-13 14:40:22 回复(2)
        B选项错在将"hello"放入指针数组,从而指针数组在内存中保存的值为olleh-6f6c6c6568,pData->data[0]是获取指针数组中的第一个char*,而我们知道一个指针占4字节,所以pData->data[0]=6c6c6568,而如果以%s的形式输出,会被解释成pData->data[0]=“xxxx”data[0]保存“xxxx”字符串的 首地址而不是具体的“xxxx”,而输出也需要访问该地址,但由于访问的地址6c6c6568是非法内存地址,所以访问会报错。若以%c输出则没事,因为pData->data[0]会被解释成pData->data[0]=‘h’,即字符'h',后面的三个字节当然被忽略了,也可以试试pData->data[1],它会输出6f,即字符"o"。若以%p输出则可以看到本质,pData->data[0]=6c6c6568。
        总结一下,内存中的数据没有类型的概念,什么类型的变量去使用它它就是什么类型,  完全看你如何解释。像本例中,人家是指针数组,你把字符串赋值进去,每个字符都以ASCII码存储,它就认为数组元素中的char*所指向的地址值就是4个字节内所有字符串本身对应的ASCII码!这可不像代码中写好了char* p = “xxxx”会被转换成char* p = ("xxxx"的首地址)。
编辑于 2021-11-04 14:46:47 回复(0)
struct str_t str;
*pData=(struct data2_t*)&str;
是不是data都是str_t 里面的那个data而不是data3_t里面的data,因为定义时暗度陈仓了

b[1]={"hello"};,那么这个hello是存放在常量区的,并不是存放在栈空间里的,不信可以试试修改这个字符串,是会报错的。而实际上存放在栈上的是指向这个字符串的指针的值。“现在题中  强行把原来存放指针的地方写入"hello",那么在取出这个指针的时候,会取出四个字节的地址空间把它解析成指针值”     snprintf(str.data,str.len,"hello")着说明hello存放在data【32】中

上图


data是一个数组,有一个元素,该元素的类型为指针类型,所以data[0]原本就是一个指针,值是一个地址,该地址占据了4个字节,假设data的首地址为8,那么地址8,9,10,11原本都存放着这个地址(这个地址指示的内存单元就存储着对应的字符串),直接输出data[0]相当于输出这个地址指向的字符串(字符串的特殊性质)。后面,这个本来存放地址的地方被hell覆盖了,地址8,9,10,11里存放的不是地址了,而是四个字符hell,如果仍然以地址类型即指针类型去指示data[0]应该获取多少字节的数据,程序就崩了


编辑于 2020-03-09 14:03:49 回复(1)
我看到很多人对b选项有疑问,在此说一下我的看法,如果有错误还请指出。data是一个指针数组,每一个元素为一个指向字符串的指针,如果用该数组来存放字符串,比如char *b[1]={"hello"};,那么这个hello是存放在常量区的,并不是存放在栈空间里的,不信可以试试修改这个字符串,是会报错的。而实际上存放在栈上的是指向这个字符串的指针的值。现在体重强行把原来存放指针的地方写入"hello",那么在取出这个指针的时候,会取出四个字节的地址空间把它解析成指针值,h二进制01101000,e二进制01100101,l二进制01101100,我的电脑是小端模式,指针的值是整形数字,那么取出来的时候就是01101100 01101100 01100101 01101000,转换成十进制是1819043176,这就是printf("%s",t2->data[0]);时访问的理论地址,显然这是个野指针,就报错了,大家可以打印验证一下,printf("%d",t2->data[0]);应该和我上面那个是一样的。
发表于 2018-06-07 22:14:34 回复(1)
B选项应该先取地址再强转
发表于 2015-09-15 08:57:38 回复(0)
为什么提示写入str.data的时候缓冲区溢出
发表于 2024-08-01 12:08:05 回复(0)
头文件少了string.h吧
发表于 2023-03-11 15:37:25 回复(0)
即指针指向谁,解引用后 (左值,右值,取值操作与 指向的对象本身操作无异)
int a[100]; int * p;  p = &a[10];  
指针p解引用为 *p;    当对指针解引用取址操作  &(*p)时,得到的地址 与 &a[10]等价;


发表于 2022-02-24 09:56:03 回复(0)
高赞解释很清楚了,我给个结论可以直接得到答案为B:

题意是用其他的struct指针来调用原结构体的成员,按照%s输出字符串,因此printf内必须是指针(即数组名或数组首地址)才行,只有B选型不是:B选型是输出地址为h的字符串,即根据h的ASCII来寻找,指向的是未知的东西。

编辑于 2020-02-25 22:22:27 回复(0)
核心在于把hello的首地址传过来。
发表于 2020-02-15 09:08:22 回复(0)
data3的那个数组都没有声明数组纬度。。。
发表于 2019-12-05 07:37:24 回复(0)