【问题标题】:Passing fscanf / sscanf string into a structure field char[4]将 fscanf / sscanf 字符串传递到结构字段 char[4]
【发布时间】:2017-01-20 05:26:40
【问题描述】:

下面的两个结构字段定义如何相互区分。

//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
...

【问题讨论】:

  • char name[4]; --> char name[5]; 或更多。另外您需要在使用前分配s1.name

标签: c struct scanf


【解决方案1】:

两个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

【讨论】:

    【解决方案2】:

    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 之后的字符。

    要解决此问题,请调整名称组件的大小。

    顺便说一句:对文件进行无限制读取可能会导致通过缓冲区溢出攻击您的软件。

    【讨论】:

      猜你喜欢
      • 2011-01-21
      • 1970-01-01
      • 2014-09-07
      • 1970-01-01
      • 1970-01-01
      • 2016-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多