读书人

请问几个C语言中困惑已久的有关问题

发布时间: 2012-02-12 17:16:33 作者: rapoo

请教几个C语言中困惑已久的问题?
进来用C语言,看程序时几个问题一直感觉比较困惑,想请教一下,仍然以昨天发帖的那个问题为例子:
#include <stdio.h>

typedef const char BYTE;
/********************/
//结构定义
typedef struct
{
BYTE *memstr;
}Item;

typedef struct
{
Item *(*grp)[2];
}Page;

//声明常量
Item Item_A=
{
"mem_A_str "
};

Item Item_B=
{
"mem_B_str "
};

Item *Group[]=//定义数组
{
&Item_A,
&Item_B,
};

/***********/
Page Page_A[]=//定义数组
{
&Group,
};

int main(void)
{
printf( "ex=%s\n ",(*Page_A[0].grp[0])-> memstr);
return 0;
}

对上面的这一段程序,我用gcc编译了,没有问题,有一下几个问题想请教:
1、最上面的const char,我原来是定义成unsigned char,编译提示错误,为什么?我在keil用cx51编译是可以的,而且重来都是用unsigned char来表示BYTE的。

2、数组Page Page_A的定义里面,为什么要在Group前面加&,数组名称不是就是一个地址吗?为什么还要这个运算符,不加的话,gcc的确提示错误,但很困惑。

3、在Item *(*grp)[2];这个定义中,后面的大小2为什么不能省略,省略以后gcc提示错误,但是,在这里为什么一定要指定大小,按道理应该不指定也可以呀?关键是,实际当中,我的确需要一个不指定大小的指针定义,我改如何做?

4、另外一个问题是,这样定义的那些数组,是否会放到内存当中区,我一直比较困惑,PC机上面的程序,看原理好像是全部导入内存才运行的,在keil当中,可以定义成code(昨天提的一个问题就是被keil的这个code给花了一天时间),放到ROM当中,是否在PC机上面没有这样的概念?


先就这样,其实还有几个,不过太多提问怕乱了,新手上路,请多指教!

[解决办法]
第一个问题:
Item Item_A=
{
"mem_A_str "
};
初始化时,实际传入的是一个const char *类型,与你原定义类型不符。
[解决办法]
第二个问题:
与你奇怪的定义Item *(*grp)[2];有关系,感觉定义的grp数组成员应是一个三级指针。
改为Item **grp[2];就没有这个困惑了。

[解决办法]
...God!
编译的时候,结构体内部变量不指定大小?~那编译器如何在编译时刻分配空间给这些定义的全局变量?所以,这个数组大小是一样要指定的!
如果不是在定义一个数组的时候立刻赋初值,那么必然要在定义的时候,指定数组大小!
除非是使用extern表示仅仅是在声明.
[解决办法]
1、最上面的const char,我原来是定义成unsigned char,编译提示错误,为什么?我在keil用cx51编译是可以的,而且重来都是用unsigned char来表示BYTE的。

报错,需要联系上下关系检查,说明是你的语法什么地方弄错了.
你在定义的时候时候是这样定义
typedef struct
{
unsigned char *memstr;
}Item;


然后又定义了常量,请注意这里是定义.
//声明常量
Item Item_A=
{
"mem_A_str "
};
那么unsigned char 表示常量吗?肯定不是,所以会报错.因为结构体内,你定义的是一个字符指针,并非字符数组.如果你定义的是
typedef struct
{
unsigned char memstr[64];
}Item;

那么就不会报错.

2、数组Page Page_A的定义里面,为什么要在Group前面加&,数组名称不是就是一个地址吗?为什么还要这个运算符,不加的话,gcc的确提示错误,但很困惑。

这里的错误用上面的方法依然可以检测出来,就是类型的匹配问题.
如果没有&,那么你这样定义的意思就是
Item *(*grp)[2] = Group;
简化一下就是
Item *(*grp)[2];
grp = Group;
Group的类型是Item *[2];
而grp的类型是Item **[2];
当然会报错.所以一定要加上&

3、在Item *(*grp)[2];这个定义中,后面的大小2为什么不能省略,省略以后gcc提示错误,但是,在这里为什么一定要指定大小,按道理应该不指定也可以呀?关键是,实际当中,我的确需要一个不指定大小的指针定义,我改如何做?

这个在上面的回帖里面已经说明了.因为这里是结构体定义,不是声明,所以必须给出数组大小.
如果需要一个不指定大小的指针,那直接定义成 Item **grp;使用的时候用molloc分配空间给grp就OK.

4、另外一个问题是,这样定义的那些数组,是否会放到内存当中区,我一直比较困惑,PC机上面的程序,看原理好像是全部导入内存才运行的,在keil当中,可以定义成code(昨天提的一个问题就是被keil的这个code给花了一天时间),放到ROM当中,是否在PC机上面没有这样的概念?

我对keil不熟,但是我相信你说的code是指MakeFile,它会将所有的程序代码,全局变量等等放入一段连续的空间内,对于单片机来说这个空间地址是已知,也是一开始就会划分好的.
不止单片机,对于已完成编译的C程序,会取得4块内存区域,一块存放程序代码,一块存放全局变量,后面的就是堆,栈.


在这方面,计算机上的编译器和keil是没有什么太大的区别的.
[解决办法]
1.我认为第一个你定义成 unsigned char 是可以的,比如:char * p= "hello ",传的是地址;
2.在Page结构里面你定义的grp是一个指针,没有定义数组,只不过这个指针指向一个数组(数组指针),而这个数组又是个指针(指针数组),这个2不能省略是因为你Group的定义,Group是个有2个元素的指针数组;
3.要求在group前面加上一个&,原因是:
Group是一个指针数组的数组名,Group+1指向Group[1],就像snake1234(川流不息)说的,它指向Item *,而对于grp,其是个数组指针,而grp+1指向下一个相邻的数组,与二维数组a[][]中的a,a+1类似,显然二者指向不一致,需要调整,这就要求相互之间赋值时,类型要求一致。

在此,我想问一个问题,在你的一个结构定义中
Page Page_A[]=//定义数组
{
&Group,
};
我认为下面定义才是正确的:
Page Page_A[]=//定义数组
{
{ &Group },
};
给结构赋值类型不是要求一致吗?但lz说编译通过了,望各位能帮忙解释一下,谢谢!
[解决办法]
1、请注意Item_A中使用的是用常量 "mem_A_str "赋值给指针。而Item_A是Item类型的,在Item中用的是BYTE*类型。这样写的话,可能需要用const来修饰。
原因是:当 指针被常量初始化时,就意味着这个指针指向的是一个text段之类的只读空间,这里的数据是在编译时便写入的,不可修改的,因此某些编译器会要求显式的用const来修饰。
例如:
char *str = "hello world ";这里的str即指向一个常量地址
你可以写成如下形式,便可以修改了。
char str[] = "hello world ";这样写的话,程序执行时,字符串会先从text段复制到运行时分配的str字符串空间,这个空间是运行时从栈中分配的。

2、请注意定义:Item *(*grp)[2];不论是否有那对小括号,都不影响结合律的结果。这里定义grp是一个指向数组的双重指针。而Group只是一个一重指针,跟定义不符。

3、c不接受可变大小的数组,因为c的数组是运行时从栈中得到,而不是从堆取得,必须在声明时明确说明维度和尺寸。
这里可以用指针来代替,在使用时 实时分配。写成
Item ***grp;

4、对keil不太了解,不过一般的c程序在装载前的状态跟在ROM中是一样的啊。只有被加载启动后,才能够被执行。这时候是需要被分配资源的。加载好的程序叫做进程。通常,程序的运行都离不开内存。
[解决办法]
c 专家编程,c陷阱和缺陷,c和指针,c primer plus(这本是入门级,讲的比较全面,很厚),
K&R的不要看了,新的标准和那个有些不同。

读书人网 >C语言

热点推荐