【问题标题】:simple c scanf is not reading and parsing my input简单的 c scanf 没有读取和解析我的输入
【发布时间】:2020-05-29 01:01:09
【问题描述】:

我创建了Date struct 来存储日期格式为datemonthyear,由用户输入为由空格分隔的单行字符串。

我想拆分输入并相应地存储它。我使用了简单的 C sscanf() 将我的输入拆分并存储在 struct Date 中。但是当我尝试打印我的数据时,它显示了一些垃圾值,我不知道缺少什么。

帮我解决这个问题。

我的代码:

Input: 24 Jan 1980
output: 24 ? -978635323 

这是我的 C 代码。

struct Date 
{
  int date;
  char* month;
  int year;
};

int main()
{
  struct Date date[1];
  char* string;
  scanf("%s",string);
  sscanf(string,"%d %s %d",&date[0].date,date[0].month,&date[0].year);
  printf("%d %s %d",date[0].date,date[0].month,date[0].year);
  return 0;
}

提前致谢。

【问题讨论】:

  • 需要为字符串分配内存。例如char *string = malloc(MY_MAX_LEN); 目前您的代码没有设置string,因此它是一个垃圾/无效指针,使用scanf 写入它会导致未定义的行为。
  • string 被声明为一个指针。指针是一个变量,用于存储某些内存的地址。因此,您需要一些内存(例如 malloc 提供的内存),并且您需要将 string 设置为该内存地址。
  • strdup() 呢?
  • strdup 需要从中复制原始字符串。您没有原始字符串。您正在阅读来自STDIN 的内容。
  • 除了为字符串分配内存(而不是指针),考虑使用fgets而不是scanf

标签: c struct scanf


【解决方案1】:

char* string 是一个未初始化的指针,它不能保存一个字符串,你需要分配内存,将它初始化为一个字符数组或将它指向一个已经分配内存的变量或一个现有的字符数组。 您的结构成员 month 也遇到了同样的问题。

编译器中的-Wall 标志应该会给你一个警告:

'string is used uninitialized in this function [-Wuninitialized]'

另一个问题是%s 只获取一个字符串,当它找到一个空格时,它会停止读取,所以在你的情况下它只能读取24

虽然"%[^\n]s" 可以工作,但更好的解决方案是使用fgets,这是一个更安全的功能,因为您可以将输入的大小限制为接收容器的大小,这与scanf 不同。

#include <stdio.h>
#define SIZE 100

struct Date 
{
  int date;
  char month[SIZE];
  int year;
};

int main()
{
  struct Date date[1];
  char string[SIZE];
  fgets(string, sizeof(string), stdin); 
  sscanf(string,"%d %s %d",&date[0].date, date[0].month, &date[0].year);
}

【讨论】:

    【解决方案2】:

    解释

    在您的代码中,您声明了两个char * 指针char *monthchar *string,并尝试在其中存储字符串值。您必须了解这两个仅仅是指针。它们只能存储char 数组的内存地址。在 C 语言中,数组变量确实可以与指针互换,但数组声明还涉及到 size 属性。

    当你将一个字符数组声明为:

    char str[10];
    

    它实际上在内存中保留了一个大小为10的块,隐式创建char *str,并将新创建的块的基地址存储在str中。但是当你只声明char *str 时,它所做的只是创建一个指针。该数组没有任何关联的内存块。

    这就是为什么你必须在使用scanf() 存储字符串之前声明一个一定大小的字符数组。或者您必须在声明char * 指针后使用callocmalloc 动态分配内存。只有这样你才能在其中存储一个字符串输入。

    我已修改您的代码以使其正常工作。它现在产生所需的输出。希望这会有所帮助。

    工作代码

    #include <stdio.h>
    #include <stdlib.h>
    
    struct Date 
    {
      int date;
      char month[10];
      int year;
    };
    
    int main()
    {
      struct Date date[1];
    
      char string[20];
    
      scanf("%[^\n]s",string);
      sscanf(string,"%d %s %d",&date[0].date,date[0].month,&date[0].year);
      printf("%d %s %d",date[0].date,date[0].month,date[0].year);
    
      return 0;
    }
    

    编辑

    它们本身实际上是整数(就像所有指针一样)。
    正如anastaciu 所提到的,指针本身并不等同于整数。您可以按照他的 cmets 中给出的链接获取更多知识。我曾提到过该声明来断言指针和数组声明之间的区别。

    【讨论】:

    • 指针不只是整数,比这更复杂,甚至它们的大小通常也因平台而异,见wandbox.org/permlink/BjRgO4VutCMKxzMg,也可以见Is pointer just an integer?Are pointers stored as integers?。跨度>
    • @anastaciu 我知道这个事实。为了让 OP 理解,我过于简单化了。我认为我的帖子触及了他的所有疑虑,并努力澄清这些疑虑。谢谢你的帖子。我今天学到了更多东西。很容易将指针想象为整数。我所说的原因是为了将它们与数组声明区分开来。我将对我的答案进行编辑以突出您的观点。如果您可以删除反对票,那就太好了。
    • @anastaciu 无论如何,谢谢伙计。它帮助我使答案变得更好。
    【解决方案3】:

    它对我有用。你可以检查一下。

    struct Date
    {
        int dat;
        char month[20];
        int year;
    };
    
    int main()
    {
        struct Date date[1];
        char str[20];
        scanf("%[^\n]%*c", str);
        sscanf(str,"%d %s %d",&date[0].dat,&date[0].month,&date[0].year);
        printf("%d %s %d",date[0].dat,date[0].month,date[0].year);
        return 0;
    }
    

    【讨论】:

    • 差不多了,在sscanf() 中,&amp;date[0].month 的类型为char (*)[20]%s 的类型为char*,使用date[0].month。见wandbox.org/permlink/yFelJXh9uuy4GGuO
    • 如果输入只是"\n",则scanf("%[^\n]%*c", str) 不会向str 写入任何内容,并且跟随sscanf(str, ... 会导致未定义的行为。使用fgets()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多