从用户输入的表格文本文件中读取和搜索缓冲区,并在C中显示正确的表格位置

zbdgwd5y  于 2023-03-07  发布在  其他
关注(0)|答案(2)|浏览(97)

我有一个table.txt文件:

class #1
Sect1: cat
Sect2: dog
Sect3: mouse
Sect4: bird
Sect5: squirrel

class#2
Sect1: shark
Sect2: octopus
Sect3: tuna
Sect4: eel
Sect5: dolphin

我可以读取文本文件并将其内容放入缓冲区。我提示用户输入动物,程序将搜索表格并输出动物在表格中的位置。示例如下:

Enter animal to search for: mouse
The animal mouse is located at Class #1 in Sect#3

我试图找到最好的方法来做搜索,但我不确定。谢谢大家的帮助。

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

int main()
{
    FILE* infile;
    char* buffer;
    long numbytes;
    char animal[10];
    char class[10];
    char sect[10];

    infile = fopen("table.txt", "r");

    if (NULL == infile) {
        printf("file can't be opened \n");
    }

    /* Get the number of bytes */
    fseek(infile, 0L, SEEK_END);
    numbytes = ftell(infile);

    /* reset the file position indicator to
    the beginning of the file */
    fseek(infile, 0L, SEEK_SET);

    /* grab sufficient memory for the
    buffer to hold the text */
    buffer = (char*)calloc(numbytes, sizeof(char));

    /* memory error */
    if (buffer == NULL)
        return 1;

    /* copy all the text into the buffer */
    fread(buffer, sizeof(char), numbytes, infile);
    fclose(infile);

    printf("Enter animal to search: ");
    scanf("%s", animal);

    //to do animal search
    
    printf("\nThe aninmal %s is located in %s and %s", animal, class, sect);

    /* free the memory we used for the buffer */
    free(buffer);

    // Closing the file
    fclose(infile);
    return 0;
}

我试着将每一行扫描到一个数组中,或者使用一个结构体来组织它,但是我不完全确定哪种方法是最好的。我是正确地构造了缓冲区来进行搜索,还是需要在之后解析它?

mrzz3bfm

mrzz3bfm1#

只需在缓冲区中 * 向后 * 搜索即可找到动物:

char *cp = buffer + numbytes - strlen(animal);
while( cp > buffer && strncmp( cp, animal, strlen( animal ) ) // non-zero = mismatch
    cp--;

// cp now points to the first letter of the animal. No duplicates, I hope.
if( cp == buffer )
    // not found... exit

// Use similar idea to search _backwards_ to find the preceding "Sect?" value
// and then again to find the "Class?" value...
// Use one variable to store the 'section' info, and one for the 'class'

你可以努力 * 解析 * 文件,把东西分解成指针和以空结尾的字符串的层次结构......程序会不会"活"得不仅仅是一次搜索?
(Of当然,如果缓冲区为 * null terminated *,则可以使用strstr()来查找动物,然后反向搜索局部"section"和"class"。有很多方法可以做到这一点!)
事实上,在缓冲区的末尾分配一个额外的字节是有利的,不管:

char *buffer = calloc( numbytes + 1, sizeof *buffer );

注意buffer在第一次使用时就被声明和定义了,你也可以对其他变量这样做。

    • 问题:**

1.如果fopen()失败,则不要继续执行。
2.不要在同一个FILE指针上调用fclose()两次。
3.不要从calloc()强制转换返回指针。
4. scanf("%s", animal); ==〉scanf("%9s", animal);
5.为什么要节省内存?10个字节的字符串是微不足道的!

    • 建议:**

将所有加载缓冲区的代码封装到一个函数中。传递文件名并接收回一个指向(以空结尾的)缓冲区的指针(必须是free()'d。这不仅"整理"了main(),而且您可能能够在其他项目中使用相同的"文件加载"代码。

i7uq4tfw

i7uq4tfw2#

在回顾你的项目所要做的事情时,我对你的代码做了一些重构,并引入了一个你可能熟悉也可能不熟悉的新项目,那就是一个结构。每个动物的特征(名称、类、节)似乎都适合结构数组的用法,这样你就可以读取和存储你所拥有的动物。有了这些,下面是你代码的重构版本。

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

typedef struct animal
{
    char aname[30];
    char cls[20];
    char section[10];
} animal;

int main()
{
    animal a[20];
    char genus[20];
    char cl[10];
    char buffer[40];
    char text[40];
    int count = 0;
    int found = 0;

    FILE* infile;

    infile = fopen("table.txt", "r");

    while (fgets(buffer, 40, infile) != NULL)
    {
        int word_length = strlen(buffer);

        if (word_length < 2)                    /* Handle skipping a blank line */
        {
            continue;
        }

        if (buffer[word_length - 1] == '\n')    /* Handle the newline character */
        {
            buffer[word_length - 1] = '\0';
        }
        strcpy(text, buffer);

        if (strstr(text, "Class"))              /* Check to see if this line denotes a start of a class group */
        {
            strcpy(cl, text);                   /* Store class name value to be placed into the animal structure array */
        }
        else
        {
            char * sect = strtok(text, " : ");  /* Acquire the section substring from the text string */
            strcpy(a[count].cls, cl);
            strcpy(a[count].section, sect);
            char * name = strtok(NULL, " : ");  /* Acquire the animal's name from the text string */
            strcpy(a[count].aname, name);
            count++;
        }
    }
    fclose(infile);

    while (1)                                   /* Now prompt the user to enter in an animal name */
    {
        printf("Enter animal to search or type \"quit\" to end the search: ");

        if(scanf("%s", genus) < 1)              /* scanf safeguard */
        {
            printf("Incorrect entry - please try again\n");
        }

        if (strcmp(genus, "quit") == 0)         /* Done with entries - end the program */
        {
            break;
        }

        found = 0;

        for (int i = 0; i < count; i++)
        {
            if (strcmp(a[i].aname, genus) == 0)
            {
                printf("The aninmal %s is located in %s and %s \n", a[i].aname, a[i].cls, a[i].section);
                found = 1;
                break;
            }
        }

        if (found == 0)
        {
            printf("Sorry, the animal requested was not found in the database - please try again\n");
        }

    }

    return 0;
}

以下是其中的一些亮点。

  • 由于将对字符数组(字符串)进行各种测试,因此包含"string. h"文件以访问字符串功能。
  • 定义了一个动物数据结构,该结构将能够包含您为每种动物记录的三个基本元素(名称、类别和部分)。
  • 动物结构数组被定义为包含文本文件中定义的每只动物的数据元素-选择了20的任意大小,但这可以大得多,以容纳任何数量的动物。
  • 在读取文本文件时,读取的数据记录将确定是否已达到新的类别组或是否正在读取实际动物记录。
  • 如果发现类别名称,则保存该类别,以便随后存储读取的每只动物,直到读取新的类别名称记录。
  • 对于读取的每个动物记录,将其名称、类别和部分信息放入数据结构数组元素中。
  • 从文件中读取所有动物数据后,使用"while"循环允许用户输入动物名称。
  • 对于每个找到的动物,列出其类、部分和名称,直到用户输入文字"quit"结束程序执行。

以下是使用您的数据文件在终端上输出的示例。

@Vera:~/C_Programs/Console/Animals/bin/Release$ ./Animals 
Enter animal to search or type "quit" to end the search: mouse
The aninmal mouse is located in Class #1 and Sect3 
Enter animal to search or type "quit" to end the search: dog
The aninmal dog is located in Class #1 and Sect2 
Enter animal to search or type "quit" to end the search: emu
Sorry, the animal requested was not found in the database - please try again
Enter animal to search or type "quit" to end the search: quit

如果结构对你来说是一个新概念,你可能想尝试一种不同的方法,或者现在可能是研究结构用法的时候了。无论如何,试试看它是否符合你的项目精神。

相关问题