【问题标题】:fgets() reads and stores a char form a line twicefgets() 从一行中读取并存储一个字符两次
【发布时间】:2020-10-19 10:09:05
【问题描述】:

所以我有一个文件data.txt,其中写入了随机整数,例如"17 12 5 4 16"

所以,我使用fgets() 读取这行整数并将其存储在char str [] 中。正如所料str [0] == 17,但str [1] == 7,依此类推……整数每2位存储在数组中的一个元素中,但第二位也存储在以下元素中。

示例: str [3] = 12str [4] = 2str[5] = ' '

可以做些什么来解决这个问题?

这是我非常典型的代码:

    FILE* fp = fopen ("data.txt", "r");

    int i = 0, j = 0;
    int size = fileSize(fp) + 1; // Enumerate the char numbers in file
    char str [size];
    rewind (fp);
    fgets (str, size, fp);

这是我的全部代码

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

typedef struct RATIONAL
{
    int top;
    int bottom;
} RATIONAL;

void printArray (int arr [], int count)
{
    for (int i = 0; i < count; ++i)
    {
        printf ("%d\n", arr[i]);
    }
}

int fileSize (FILE* fp)
{
    char c;
    int i = 0;
    while ((c = getc (fp)) != EOF)
    {
        i++;
    }
    return (i);
}

int main ()
{
    RATIONAL ratArray [23];  //array to hold rational numbers
    int intArray [45]; //array to hold integer values

    FILE* fp = fopen ("data.txt", "r");

    int i = 0, j = 0;
    int size = fileSize(fp) + 1; // Enumerate the char numbers in file
    char str [size];
    rewind (fp);
    fgets (str, size, fp);

    //Convert string to array of ints
    while (i < size -1)
    {
        if (isdigit (str [i]))
        {
                intArray[j++] = atoi(&str[i]);
                i++;
        }
        else
            i++;
    }
        printArray (intArray, intArray[0]);

输入:data.txt

【问题讨论】:

  • 你怎么知道每个数组元素中存储了什么?你是怎么发现的?
  • 请提供minimal verifiable example。也就是说,任何人都可以完全按照所示运行以重现确切问题的最少完整代码量。
  • 如果 array[0] 你的意思是 str[0] 那么当然它只是第一个数字。您需要提取每个 int 而不仅仅是读取每个 ascii 字符。
  • 当您edit 您的问题是为了执行第二条评论中友好地询问您的问题时,还请提供一个最小的data.txt 文件,以便重现该问题。也告诉我们array 是什么,你的代码中没有这样的符号。
  • "正如预期的数组 [0] == 17," 不! str[0] 包含 '1',因为它只能容纳 1 个 char,不能更多。

标签: c string integer


【解决方案1】:

您所经历的一切都是意料之中的。关键的误解是您希望 arr[N] 保存 (N+1)th 整数,因为它是一个整数数组......但事实并非如此。它是一个字符数组。

如果您将整数存储在char 数组中,则每个数字将占据一个数组位置。所以arr[0] 将包含第一个数字的最高有效数字,arr[a] 将包含最低有效数字。

因此,在您的示例中,字符串 "17 12 5 4 16" 将以这种方式存储:

--------------------------------------------------------------------------------------------
| 0x31 | 0x37 | 0x20 | 0x31 | 0x32 | 0x20 | 0x35 | 0x20 | 0x34 | 0x20 | 0x31 | 0x36 | 0x00 |
--------------------------------------------------------------------------------------------
|  '1' |  '7' |  ' ' |  '1' |  '2' |  ' ' |  '5' |  ' ' |  '4' |  ' ' |  '1' |  '7' | '\0' |
--------------------------------------------------------------------------------------------

所有数字都在同一个数组中,并用空格分隔。字符串由字符串终止符 '\0' 关闭。

很有趣,如果你用printf("%s\n", arr) 打印整个字符串,你会得到

17 12 5 4 16

但是如果你尝试打印传递第二个字符的地址,printf("%s\n", &amp;arr[1]) 你会得到

7 12 5 4 16

等等。这意味着 C 不知道(还不知道)您的意图是存储 5 个整数。在找到字符串终止符之前,字符串是一个(空格不会终止字符串),所以从第二个数字开始只会让 C 打印除第一个数字之外的所有字符串。


由于您有一个以众所周知的方式格式化的字符串,并且您想要一个整数数组,因此您必须对其进行解析以获取整数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char arr[] = "7 12 5 4 16";

int main()
{
    char * token = strtok(arr, " ");
    while(token != NULL)
    {
        printf("Next int: %d %s\n", atoi(token)); // Here you can assign the value to your array
        token = strtok(NULL, " ");
    }

    return 0;
}

在我的演示示例中,输入字符串是一个全局数组,而不是像在您的场景中那样从文件中读取的内容,我使用了strtok()strtok_r 可以在需要重入函数的情况下使用) 我使用简单的atoi() 得到整数(只是因为输入格式是_under control - 我建议使用strtol() 更好地控制输入)。

【讨论】:

  • 非常感谢,演示的很好。为了响应这些新知识,我在解析字符串数组时将“i++”更改为“i+=2”,并且它起作用了。我也发现你提出的方法更有效,所以我会从现在开始实施它。
  • @omarkhaled 如果对您有帮助,请随时接受答案。 ;)
猜你喜欢
  • 2012-04-08
  • 2013-06-27
  • 2014-06-25
  • 2012-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多