如何从文本文件中读取整数和字符并将它们存储在不同的数组中?

3
我正在尝试从文件中读取一行行包含字符串 "Jane 30"、"Chris 40" 等的输入。然后,我需要将每个名称及其对应的数字存储在不同数组的相同索引中,例如 "Jane" 存储在一个数组中的索引 0 处,而数字 30 则存储在整数数组的索引 0 处。
这是我目前的代码,但我无法想出如何将整数提取到单独的数组中,将字符提取到另一个数组中。请帮忙解决。
#include stdio.h
#include stdlib.h
#include DarrensInfo.

int main()
{
FILE * coinfile;
coinfile = fopen("coins.txt", "r");
char names[150];
int change[50];
int x, y;

while(!feof(coinfile)){

    fgets(names, 150, coinfile);
    y = 0;

    for(x=0; names[x]; x++){

        if(names[x] <= '0' && names[x] <= '9'){

            change[y] = names[x];
            y++;

        }
    }

}

fclose(coinfile);

return 0;
}

4
为什么“while (!feof(file))”总是错误的? - pmg
看一下sscanf函数,从读取的行中提取字符串和数字。除此之外,自己做作业总是一个好主意。 - mbieren
4个回答

2
#define COINS_MAX_LINES 150
#define MAX_LINE_LENGTH 100  
#define MAX_NAME_LENGTH 50
int main()
{
    FILE * coinfile;
    coinfile = fopen("coins.txt", "r");
    char line[MAX_LINE_LENGTH];
    char names[COINS_MAX_LINES][MAX_NAME_LENGTH];
    int change[COINS_MAX_LINES];
    int lineno = 0;
    int i = 0;
    while(fgets(line, MAX_LINE_LENGTH, coinfile))
    {
        sscanf(line, "%s %d", names[lineno], &change[lineno]);
        ++lineno;
    }

    fclose(coinfile);

    for (i = 0; i<lineno;++i)
        printf("Name = %s Change = %d\n", names[i], change[i]);

    return 0;

}

while循环结束后,names数组和change数组将包含您想要的内容。我已在第二个循环中将其打印出来。


2
change 数组的长度应该为 COINS_MAX_LINES,最好检查 scanf 的返回值(即使在示例中)。 - Hasturkun
使用没有宽度限制的 sscanf(line, "%s ... (且 MAX_LINE_LENGTH > MAX_NAME_LENGTH)会面临与 gets() 相同的问题。更好的代码避免缓冲区溢出。 - chux - Reinstate Monica

0
  1. 您需要一个字符数组的数组。将变量names定义为names[150][30],假设每个名称的长度不超过30个字符。
  2. 使用fgetsfscanf的组合,将文件中的输入行解析为所需的单独变量。
#include <stdio.h>
#include <stdlib.h>

int main()
{
  FILE * coinfile;
  coinfile = fopen("coins.txt", "r");
  char names[150][30];
  int change[150];
  int x = 0, y, i;

  char buf[100];
  while(!feof(coinfile)){
    if(fgets(buf, 100, coinfile) != NULL) { 
      sscanf(buf, "%s %d", names[x], &change[x]);
      x++;
    }
  }
  fclose(coinfile);

  puts("-------");
  for (int i = 0; i < x; i++)
    printf("%s %d\n", names[i], change[i]);

  return 0;
}

也许可以将 while(!feof(coinfile)){ if(fgets(buf, 100, coinfile) != NULL) { 简化为 while(fgets(buf, 100, coinfile)) { 吗? - chux - Reinstate Monica

0

如果您正在尝试解析可能看起来像“King Charles 3”这样的名称,则使用scanf将很困难。实际上,不使用静态大小缓冲区做这种事情并不那么困难,这是一个很好的习惯。您将要避免使用fgets,因为这很难在没有固定大小的情况下使用。请注意,增长数组非常困难,因此我对以下内容的正确性不作任何声明。每隔几个月我们都需要进行这种练习,以便提醒自己为什么我们不在C中做这种事情:

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

FILE * Fopen(const char *, const char *);
void * Realloc(void *, size_t);

/* Remove trailing whitespace */
void trim_white(char *b, char *end)
{
        while( end > b && isspace(*--end)) {
                *end = '\0';
        }
}

int
main(int argc, char **argv)
{
        char *path = argc > 1 ? argv[1] : "stdin";
        FILE *coinfile = argc > 1 ? Fopen(path, "r") : stdin;
        size_t asize = 16;
        size_t bsize = 0;
        char *buf = NULL;
        char **names = Realloc(NULL, asize * sizeof *names);
        long *change = Realloc(NULL, asize * sizeof *change);
        unsigned line_number = 0;
        ssize_t char_read;
        while( buf = NULL, (char_read = getline(&buf, &bsize, coinfile)) != -1) {
                char *space;
                char *end;
                trim_white(buf, buf + char_read);
                space = strrchr(buf, ' ');
                if(space == NULL) {
                        fprintf(stderr, "Invalid input on line %d (no space)\n", line_number + 1);
                        exit(EXIT_FAILURE);
                }
                change[line_number] = strtol(space + 1, &end, 10);
                if(*end != '\0') {
                        fprintf(stderr, "Invalid input on line %d at '%s'\n", line_number + 1, space + 1);
                        exit(EXIT_FAILURE);
                }
                *space = '\0';
                names[line_number] = buf;

                if(++line_number == asize) {
                        asize *= 2;
                        names = Realloc(names, asize * sizeof *names);
                        change = Realloc(change, asize * sizeof *change);
                }
        }

        return EXIT_SUCCESS;
}

FILE *
Fopen(const char *path, const char *mode) {
        FILE *fp = fopen(path, mode);
        if( fp == NULL ) { perror(path); exit(EXIT_FAILURE); }
        return fp;
}

void *
Realloc(void *buf, size_t s)
{
        buf = realloc( buf, s );
        if( buf == NULL) { perror("realloc"); exit(EXIT_FAILURE); }
        return buf;
}

你应该避免使用fgets,而选择使用getline()getline()的一个弱点是它允许恶意用户通过形成过长的输入行来耗尽内存资源。而fgets()则提供了一个上限。每种解决方案都有其优缺点。(另外建议使用无符号的%u) - chux - Reinstate Monica

0
我正在尝试从文件中逐行读取包含字符串“Jane 30”,“Chris 40”等的输入内容。
您正在读取一个可能包含字符串“Jane 30”,“Chris 40”等的文件;但也可能包含数百万个打字错误和/或其他错误;因此,您需要检测错误并清楚地告知用户错误是什么,以便他们可以轻松理解问题,然后找到错误并修复它。
因此,C库函数都不会有用。相反,要构建一个作为有限状态机的解析器。例如(未经测试):
    // State

    int state = 0;
    int column = 0;
    int line = 1;
    char current_name[MAX_NAME_LENGTH];
    int name_length;
    int number;

    // Main loop

    for(;;) {
        int c = fgetc(file);
        column++;
        switch(state) {

        case 0:  /* At start of new line */
            if(c == FEOF) {
                return OK;
            } else if(isdigit(c)) {
                printf("ERROR: Number found at start of line (missing name), on line %d at column %d\n", line, column);
                return NOT_OK;
            } else if(isalpha(c)) {
                name_length = 0;
                current_name[name_length++] = c;
                state = 1;
            } else if(c == '\n') {
                line++
            } else if(isspace(c)) {
            } else {
                printf("ERROR: Bad character at start of line, on line %d at column %d\n", line, column);
                return NOT_OK;
            }
            break;

        case 1:  /* In middle of name */
            if(c == FEOF) {
                printf("ERROR: File ends in the middle of a name, on line %d at column %d\n", line, column);
                return NOT_OK;
            } else if(isdigit(c)) {
                printf("ERROR: No whitespace between name and number, on line %d at column %d\n", line, column);
                return NOT_OK;
            } else if(isalpha(c)) {
                if(name_length >= MAX_NAME_LENGTH) {
                    printf("ERROR: Name too long (max length is %d), on line %d at column %d\n", MAX_NAME_LENGTH, line, column);
                    return NOT_OK;
                }
                current_name[name_length++] = c;
            } else if(c == '\n') {
                printf("ERROR: No number after name, on line %d at column %d\n", line, column);
                return NOT_OK;
            } else if(isspace(c)) {
                state = 2;
            } else {
                printf("ERROR: Bad character in middle of name, on line %d at column %d\n", line, column);
                return NOT_OK;
            }
            break;

        case 2:  /* Between name and number */
            if(c == FEOF) {
                printf("ERROR: File ends after name, on line %d at column %d\n", line, column);
                return NOT_OK;
            } else if(isdigit(c)) {
                number = c - '0';
                state = 3;
            } else if(c == '\n') {
                printf("ERROR: No number after name, on line %d at column %d\n", line, column);
                return NOT_OK;
            } else if(isspace(c)) {
            } else {
                printf("ERROR: Bad character after name, on line %d at column %d\n", line, column);
                return NOT_OK;
            }
            break;

        case 4:  /* In middle of number */
            if(c == FEOF) {
                printf("ERROR: File ends in middle of number, on line %d at column %d\n", line, column);
                return NOT_OK;
            } else if(isdigit(c)) {
                if(number > INT_MAX / 10) {
                    printf("ERROR: Number is too large, on line %d at column %d\n", line, column);
                    return NOT_OK;
                }
                number *= 10;
                if(number > INT_MAX - (c - '0') ) {
                    printf("ERROR: Number is too large, on line %d at column %d\n", line, column);
                    return NOT_OK;
                }
                number += c - '0';
            } else if(c == '\n') {
                create_new_entry(current_name, name_length, number);
                line++
                state = 0;
            } else if(isspace(c)) {
                state = 5;
            } else {
                printf("ERROR: Bad character after number, on line %d at column %d\n", line, column);
                return NOT_OK;
            }
            break;

        case 5:  /* Trailing white space before end of line */
            if(c == FEOF) {
                printf("ERROR: File ends between number and end of line, on line %d at column %d\n", line, column);
                return NOT_OK;
            } else if(c == '\n') {
                line++
                create_new_entry(current_name, name_length, number);
                state = 0;
            } else if(isspace(c)) {
            } else {
                printf("ERROR: Unknown characters between number and end of line, on line %d at column %d\n", line, column);
                return NOT_OK;
            }

        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接