C语言 我提取A,txt文件有奇怪的错误[关闭]

jxct1oxe  于 2023-04-29  发布在  其他
关注(0)|答案(1)|浏览(98)

**关闭。**此题需要debugging details。目前不接受答复。

编辑问题以包含desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将帮助其他人回答这个问题。
昨天关门了。
Improve this question
我在试着恢复。txt文件的文本,把它变成一个记录,以创建一个基本的“全球定位系统”。我确实设法把文本变成了一个记录,然而,代码运行的时间越长,出现的错误就越频繁(比如它写的是“hungry”而不是“hungry”)。

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

typedef int bool;
#define TRUE 1
#define FALSE 0

// definir string
typedef char string[1024];

//Define event
typedef struct{
  string action[49],preconds[24],add[24],delete[24];
  int NbPreconds,NbAdd,NbDelete;
}Event;

int parseLine(char source[], string cible[]){
  int i=0, n=0; // i: source[], n: cible[]
  while(source[i]!=':') i++; // go until ':'
    i++; // avancer au debut de la premiere chaine
    int j=i;  // point beginning of first chain with j
  while(source[i]!='\n'){
    if(source[i]==','){
      memcpy(&cible[n], &source[j], i-j); // extract characters from j to i
      n++;
      j=i+1;   // j beginning of chain
    }
    i++;
  }
  return n;
}

int main(){
  Event event[49];
  string start[49],finish[49];
  int NbStart,NbFinish,i,k,x,Z;
  char source[100];
  FILE* txtfile = fopen("school.txt","r"); // insérer "monkeys.txt" / "blocs.txt" / "school.txt" pour choisir le fichier
  if(txtfile == NULL){ // tester le fichier s'il existe
    printf("Fichier inexistant.\n");
    exit(0);
  }
  else{
    printf("Fichier ouvert.\n");
  }
  //Lire les Conditions de départ & de Fin
  fgets(source,100,txtfile);
  NbStart=parseLine(source,start);
  printf("Condition Départ:\n");
  for(i=0; i<NbStart;i++){
    printf("  - %s\n",start[i]);
  }
  fgets(source,100,txtfile);
  string tempo[]={""};
  NbFinish=parseLine(source,finish);
  printf("Condition Fin:\n");
  for(i=0;i<NbFinish;i++){
    printf("  - %s\n",finish[i]);
  }
  //read action
  int NbE=0;
  while(fgets(source,100,txtfile)!=NULL){
    fgets(source,100,txtfile);
    parseLine(source, event[NbE].action);

    //read preconds
    fgets(source,100,txtfile);
    event[NbE].NbPreconds=parseLine(source, event[NbE].preconds);
    for(i=0;i<event[NbE].NbPreconds;i++){
      printf("Precond: %s\n",event[NbE].preconds[i]);
    }

    //read add
    fgets(source,100,txtfile);
    event[NbE].NbAdd=parseLine(source, event[NbE].add);
    for(i=0;i<event[NbE].NbAdd;i++){
      printf("Add: %s\n",event[NbE].add[i]);
    }
    //read delete
    fgets(source,100,txtfile);
    event[NbE].NbDelete=parseLine(source, event[NbE].delete);
    for(i=0;i<event[NbE].NbDelete;i++){
      printf("Delete: %s\n",event[NbE].delete[i]);
    }
  }
  bool Test=0; //Not complete
  while(Test==0){
    Test=1;
    for(i=0;i<NbStart;i++){
      for(k=0;k<NbStart;k++){
        if(start[k]==finish[i]){
          Z++;
          if(Z==NbFinish){
            Test=1;
          }
        }
      }
    }
    Z=0;
  }
  if(Test==1){
    printf("Le résultat a était trouvé en %d étapes.\n",x);
  }
  fclose(txtfile);
}

输入:

start:at door,on floor,has ball,hungry,chair at door,
finish:not hungry,
****
action:climb on chair,
preconds:chair at middle room,at middle room,on floor,
add:at bananas,on chair,
delete:at middle room,on floor,
****
action:push chair from door to middle room,
preconds:chair at door,at door,
add:chair at middle room,at middle room,
delete:chair at door,at door,
****
action:walk from door to middle room,
preconds:at door,on floor,
add:at middle room,
delete:at door,
****
action:grasp bananas,
preconds:at bananas,empty handed,
add:has bananas,
delete:empty handed,
****
action:drop ball,
preconds:has ball,
add:empty handed,
delete:has ball,
****
action:eat bananas,
preconds:has bananas,
add:empty handed,not hungry,
delete:has bananas,hungry,

输出:

Fichier ouvert.  
Condition Départ:
  - at door      
  - on floor
  - has ball
  - hungry
  - chair at door
Condition Fin:
  - not hungry
Precond: chair at middle room
Precond: at middle room
Precond: on floor
Add: at bananas
Add: on chair
Delete: at middle room
Delete: on floor

Precond: chair at doorle room
Precond: at doorle room
Add: chair at middle room
Add: at middle room
Delete: chair at doorm
Delete: at doorr

Precond: at doort doorle room
Precond: on floore room
Add: at middle roome room
Delete: at doort doorm

Precond: at bananasoorle room
Precond: empty handedom
Add: has bananasoome room
Delete: empty handedrm

Precond: has ballasoorle room
Add: empty handedome room
Delete: has ballndedrm

Precond: has bananasorle room
Add: empty handedome room
Add: not hungryroom
Delete: has bananasdrm
Delete: hungryrr

Le résultat a était trouvé en 0 étapes.
axzmvihb

axzmvihb1#

如何使用GNU调试器查找bug

下面是一个如何使用GNU debugger(GDB)查找bug的示例。如果您使用的是带有另一个调试器的IDE,也可以使用该调试器。所有调试器都应该具有下面描述的功能,尽管语法可能不同。此外,一些调试器允许您通过鼠标单击按钮来发出命令,而不是键入命令。
在您发布的输出中,第一行不正确的是以下行:

Precond: chair at doorle room

它应该是:

Precond: chair at door

这一行输出由代码行打印

printf("Precond: %s\n",event[NbE].preconds[i]);

event[NbE].preconds[i]应该由行设置

event[NbE].NbPreconds=parseLine(source, event[NbE].preconds);

也就是程序中的两行。是69号线。
因此,我们将您的程序加载到GDB中,并使用以下GDB命令在第69行设置断点:

b 69

然后,我们开始使用

r

命令
程序现在将运行到第一次到达第69行上的断点。
我们现在使用以下命令设置GDB,使其在程序停止时显示event[NbE].preconds的值:

display event[NbE].preconds

GDB现在告诉我这个变量有以下值:

1: event[NbE].preconds = {'\000' <repeats 1023 times> <repeats 24 times>}

这意味着2D数组中所有数组的所有元素都具有值0。它可能会告诉你同样的情况,尽管这并不能保证,因为你没有以任何方式初始化这些值。
现在我们通过使用以下命令跳过函数调用,转到下一行:

n

GDB现在告诉我们关于event[NbE].preconds的以下内容:

1: event[NbE].preconds = {"chair at middle room", '\000' <repeats 1003 times>, "at middle room", '\000' <repeats 1009 times>, "on floor", '\000' <repeats 1015 times>, '\000' <repeats 1023 times> <repeats 21 times>}

这些由parseLine创建的字符串看起来很好,所以我们继续运行程序,直到再次到达断点,使用以下命令:

c

GDB告诉我们,event[NbE].preconds自上次程序停止以来没有被更改,所以我们使用以下命令再次跳过函数调用parseLine

n

GDB现在告诉我们,event[NbE].preconds已更改为以下值:

1: event[NbE].preconds = {"chair at doorle room", '\000' <repeats 1003 times>, "at doorle room", '\000' <repeats 1009 times>, "on floor", '\000' <repeats 1015 times>, '\000' <repeats 1023 times> <repeats 21 times>}

此值不正确。所以我们现在知道第二时间线69被执行,函数parseLine将给予我们无效的结果。因此,我们使用命令重新启动程序

r

我们告诉GDB,我们不再希望每次程序停止时都被告知event[NbE].preconds的值,通过使用以下命令:

undisplay 1

现在我们重复上面的步骤,除了display命令之外,但是在第二次遇到第69行的断点时,我们没有使用n命令跳过对parseLine的函数调用,而是使用

s

命令进入函数调用,这样我们就可以确切地看到函数是如何生成错误的输出的。
进入函数后,我们发出命令

display cible[0]

来监视该字符串的内容。
发出命令后

n

跳到下一行几次(您可以简单地按Enter重复上一个命令),我们看到在该函数中对memcpy的调用将更改cible[0]的内容

chair at middle room

致:

chair at doorle room

我们看到memcpy覆盖了cible[0]的前13个字符,但没有写入空终止字符。因此,字符le roommiddle room的残余,middle room是字符串先前内容的一部分。
函数parseLine的其余部分也从不向字符串写入终止null字符,因此错误的字符串最终会被传回并打印出来。
因此,我们现在知道,最明显的修复方法是函数parseLine在调用memcpy之后向字符串添加一个终止空字符。

相关问题