下面的两个结构字段定义如何相互区分。
//first struct
typedef struct{
char *name; //here is the difference
int shares;
} STOCK1;
//second struct
typedef struct{
char name[4]; //here is the difference
int shares;
} STOCK2;
//here inside main()
FILE *fpRead = openFile(input_filename, "r");
STOCK1 s1;
fscanf(fpRead, "%s %d", s1.name, &s1.shares);
printf("%s %d ", s1.name, s1.shares);
STOCK2 s2;
fscanf(fpRead, "%s %d", s2.name, &s2.shares);
printf("%s %d ", s2.name, s2.shares);
代码将打印出来:
MSFT 400
MSFT� 400
正如您所看到的,使用第二个结构,它将在字符串后打印一些垃圾字符。那是为什么?
输入字符串:
MSFT 400
YHOO 100
...
答案 0 :(得分:1)
STOCK2.name
的大小为4个字符。你的字符串有4个字符+终止符\0
。这是5个字符。因此终结符位于与shares
组件重叠的结构组件后面。如果设置shares
组件,它将覆盖字符串终止符。
让我们有一个示例布局来说明这一点(32位/ 4字节整数)。写完名字后:
n+0 name[0] M
n+1 name[1] S
n+2 name[2] F
n+3 name[3] T
n+4 shares \0 <- terminator
n+5 shares
n+6 shares
n+7 shares
n+0 name[0] M
n+1 name[1] S
n+2 name[2] F
n+3 name[3] T
n+4 shares 144 | Example for 400 stored in a 32-bit int (144+1*256)
n+5 shares 1 |
n+6 shares 0 |
n+7 shares 0 |
终止符消失,printf()
继续在T之后写出字符。
要解决此问题,请调整名称组件的大小。
BTW:从文件中无限制地读取可以在缓冲区溢出的情况下攻击您的软件。
答案 1 :(得分:1)
2个struct
定义之间的区别在于,您在一个struct
中预先分配存储空间,并在另一个struct
中声明指针。
在您的第一个struct
中,您有char *
。 char *
是一个指针。它没有指向任何东西。您需要动态分配一些内存,然后将char *
指针指向该分配的内存。
在您的第二个struct
中,您有char name[4]
。这是一个数组,您将为此数组分配4个字节。这已分配并可以使用。
如果您事先不知道缓冲区的大小,请使用第一个struct
。使用malloc
分配任意数量的内存,例如1024字节。然后一次读入1024字节的数据。继续这样做,直到你可以计算出数据总量有多大,然后用malloc
分配那么多的内存,然后读入你的数据。
如果你知道你的数据总是4个字节长,并且它永远不会大于或小于那个数据,那么使用第二个struct
。如果需要,可以这样声明:char name[500]
。这将为您预先分配500个字节,只要您的字符串不超过499个字符,这将起作用。但是,你可能会浪费记忆(这些日子并不是什么大问题)。解决此问题的最有效方法是使用malloc
最后一个警告....请记住,C中的字符串需要足够的内存用于字符串本身,加上一个空终止符。例如:
/* I am allocating 5 bytes to store my name.
My name is Alan, so I'm allocating 4 bytes
plus 1 additional byte for the null terminator
*/
char myName[5];
myName[0] = 'A'; // A
myName[1] = 'l'; // l
myName[2] = 'a'; // a
myName[3] = 'n'; // n
myName[4] = '\0'; // Null Terminator
printf("%s", myName); // Prints Alan