从txt.file读取到链表,需要帮助纠正代码

时间:2017-06-28 20:01:51

标签: c

我在获得正确的输出方面遇到了问题,列表搞砸了。

1.我被告知在较小的部分打破我的while循环会有所帮助,但我似乎无法做到正确。 问题:打印时在某些列之间弹出一个数字“1”,在代码的下方用“-858993460”替换。 为什么会这样?

我的目标:“机器人”“Termintortyp”“idnr”\ n

AKA:“终结者”“T-800 / T-1000”“1-100”

2.我还想添加错误检查:

如果出现错误 - >打印错误消息,然后代码应继续,直到链表已用完。例如:11到12行之间它表示“FEL FEL FEL”或第16行“_____TERMINATOR T-1000 16”。如果在将txt.file读入链表时可以识别问题,并以某种方式替换“错误的终结者” - 带有错误信息的行可以解决我的问题,但我不知道如何正确地做到这一点。 有任何建议吗?

感谢我能得到的所有帮助!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Link {
char robot[12];
char terminatortyp[10];
int idnr;
struct Link *next;
};
typedef struct Link Link;
Link *first = NULL;

int main(void) {
int antal = 0;
Link a;
FILE *tsin = fopen("textfil1R.txt", "r");
if (tsin == NULL) {
    printf("Kunde inte läsa filen 'textfil.txt'.\n");
    exit(EXIT_FAILURE);
}

Link *temp;

while (fgets(a.robot, sizeof a.robot, tsin) != NULL)
{
    temp = malloc(sizeof(Link));
    strcpy(temp->robot, a.robot);

    fgets(a.terminatortyp, sizeof a.terminatortyp, tsin);
    strcpy(temp->terminatortyp, a.terminatortyp);


        fscanf(tsin, "%d", &a.idnr);
        temp->idnr = a.idnr;

        temp->next = first;
        first = temp;

        ++antal;

    }
fclose(tsin);


    Link *p = first;
    while (p != NULL)
    {
        //printf("%d\n", p->idnr);
        printf("%s", p->robot);
        printf("%s", p->terminatortyp);
        printf("%d\n", p->idnr);
        p = p->next;

    }
    printf("%d", antal);
    getch();
    return 0;
}

我正在阅读的文本文件:

TERMINATOR T-800 1
TERMINATOR T-1000 2
TERMINATOR T-800 3
TERMINATOR T-800 4
TERMINATOR T-1000 5
TERMINATOR T-800 6
TERMINATOR T-800 7
TERMINATOR T-800 8
TERMINATOR T-1000 9
TERMINATOR T-800 10
TORMONUTTUR T-800 101
TERMINATOR T-800 11
FEL FEL FEL
TERMINATOR T-1000 12
TERMINATOR T-800 13
TERMINATOR T-800 14
TERMINATOR           T-800         15
       TERMINATOR T-1000 16
TERMINATOR T-800 17                       
TERMINATOR T-800 18
TERMINATOR T-1000 19
TERMINATOR T-800 20
TERMINATOR T-800 21
TERMINATOR T-800 22
TERMINATOR T-1000 23
TERMINATOR T-800 24
TERMINATOR T-800 25
TERMINATOR T-1000 26
TERMINATOR T-800 27
TERMINATOR T-800 28
TERMINATOR T-800 29
TERMINATOR T-1000 30
TERMINATOR T-800 31
TERMINATOR T-800 32
TERMINATOR T-1000 33
TERMINATOR T-800 34
TERMINATOR T-800 35
TERMINATOR T-800 36
TERMINATOR T-1000 37
TERMINATOR T-800 38
TERMINATOR T-800 39
TERMINATOR T-1000 40
TERMINATOR T-800 41
TERMINATOR T-800 42
TERMINATOR T-800 43
TERMINATOR T-1000 44
TERMINATOR T-800 45
TERMINATOR T-800 46
TERMINATOR T-1000 47
TERMINATOR T-800 48
TERMINATOR T-800 49
TERMINATOR T-800 50
TERMINATOR T-1000 51
TERMINATOR T-800 52
TERMINATOR T-800 53
TERMINATOR T-1000 54
TERMINATOR T-800 55
TERMINATOR T-800 56
TERMINATOR T-800 57
TERMINATOR T-1000 58
TERMINATOR T-800 59
TERMINATOR T-800 60
TERMINATOR T-1000 61
TERMINATOR T-800 62
TERMINATOR T-800 63
TERMINATOR T-800 64
TERMINATOR T-1000 65
TERMINATOR T-800 66
TERMINATOR T-800 67
TERMINATOR T-1000 68
TERMINATOR T-800 69
TERMINATOR T-800 70
TERMINATOR T-800 71
TERMINATOR T-1000 72
TERMINATOR T-800 73
TERMINATOR T-800 74
TERMINATOR T-1000 75
TERMINATOR T-800 76
TERMINATOR T-800 77
TERMINATOR T-800 78
TERMINATOR T-1000 79
TERMINATOR T-800 80
TERMINATOR T-800 81
TERMINATOR T-1000 82
TERMINATOR T-800 83
TERMINATOR T-1001 84
TERMINATOR T-800 85
TERMINATOR T-1000 86
TERMINATOR T-800 87
TERMINATOR T-800 88
TERMINATOR T-1000 89
TERMINATOR T-800 90
TERMINATOR T-800 91
TERMINATOR T-800 92
TERMINATOR T-1000 93
TERMINATOR T-850 94
TERMINATOR T-800 95
TERMINATOR T-1000 96
TERMINATOR T-800 97
TERMINATOR T-800 98
TERMINATOR T-800 99
TERMINATOR T-1000 100

2 个答案:

答案 0 :(得分:1)

您正在使用fgets,就好像它将在单个字符串中读取,直到下一个空格。然而,fgets读取完整的行,直到它检测到换行符'\n'或到达文件的末尾。

所以在声明fgets(a.robot, sizeof a.robot, tsin)之后,a.robot的值可能是TERMINATOR T-800 17\n而不是TERMINATOR。这一方面导致缓冲区溢出,并且循环中重复的fgets语句实际上以完整的行读入当前的temp对象。

while (fscanf(tsin, "%11s %9s %d", a.robot, a.terminatortyp, &a.idnr) == 3)
{
    temp = malloc(sizeof(Link));
    strcpy(temp->robot, a.robot);
    strcpy(temp->terminatortyp, a.terminatortyp);
    temp->idnr = a.idnr;

    temp->next = first;
    first = temp;

    ++antal;
}

请注意最大字段宽度说明符%11s,以确保最多读入11个字符(+一个额外的字符串终止符),以便扫描适合大小为12的缓冲区。例如,cppreference/scanf

  

%11s:如果使用宽度说明符,则匹配宽度或直到第一个   空白字符,以先出现者为准。始终存储空值   字符除了匹配的字符(所以参数数组   必须有至少宽度+ 1个字符的空间)

答案 1 :(得分:1)

使用fgets()阅读,而不是单词。

char line[100];
while (fgets(line, sizeof line, tsin) != NULL) {

现在解析这一行。使用%n来保存扫描的偏移量 - 如果它到达那么远。请务必限制成员可接受的字符的最大宽度。可以进行额外的检查。这将帮助您入门。

  struct Link entry = { 0 }; // zero fill members
  int n = 0;
  int lead;
  sscanf(line," %n%11s%9s%d %n",&lead, entry.robot, entry.terminatortyp, &entry.idnr, &n);
  // All specifiers scanned and no extra junk? 
  if (n == 0 || line[n]) {
    printf("Bad line <%s>\n", line);
    continue;
  }
  if (lead > 0) {
    printf("leading spaces <%s>\n", line);
    continue;
  }

根据需要为成员添加健全性检查。

  if (entry.idnr < 1 || entry.idnr > 9999) {
    printf("Bad index <%s>\n", line);
    continue;
  }

成功,现在分配

  struct Link *node = malloc(sizeof *node);
  if (node == NULL) {
    printf("Out of memory at line <%s>\n", line);
    break;
  }
  *node = entry;
  node->next = first;
  first = node;
}
  

有什么建议吗?

@ imanoob,duärinteen noob