【问题标题】:Program works with string literals but not with string arrays程序适用于字符串文字,但不适用于字符串数组
【发布时间】:2014-07-13 11:05:04
【问题描述】:

我有一个哈希表 ADT,它有两个函数,插入和查找。我在插入函数中输入了一个哈希表、哈希表大小、ID # 和书名,然后将其插入到哈希表中。当我将字符串文字传递给它时,这很好用,即insert(...,"Hello, world!"...); 当我从文件中读取字符串,将它们存储在数组中并尝试使用我的插入和查找函数时,它不起作用。 我的所有代码都在这里,但最重要的文件是 main.c 和 hash.c。 Hash.c 具有 newHash()、hash()、insert() 和 lookup() 函数,并且 main.c 从两个文件读取,在本例中为 test1.lib.in 和 test1.req.in,并从第一个file 将从每一行获取一本书的图书馆 ID 和标题,然后将其放入哈希表中。从第二个文件中,它获取书名请求,并应打印其链接列表中的 ID。

有效的代码示例。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "list.h"
#include "hash.h"

int main(){
    ListHndl* temp = newHash(10);
    insert(442440, "cvyaqbznxel", 10,temp);
    lookup(temp,"cvyaqbznxel", 10);
    return 0;
}

无效的代码

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "list.h"
#include "hash.h"


int main(int argc, char * argv[]) {

    if (argc != 3) {
        printf("Incorrect arguments, please specify 2 files to be read\n");
        return EXIT_FAILURE;
    }
    FILE *file = fopen( argv[1], "r");
    FILE *secondFile = fopen(argv[2], "r");
    if (file == 0 || secondFile == 0) {
        printf("Could not open a file\n");
        return EXIT_FAILURE;
    }
    int numDataLines2;
    int numDataLines;
    int hashTableSize;
    //First line of first file gives number of lines in file and 
    //size of hash table to be made
    if(fscanf(file, "%d%d", &numDataLines, &hashTableSize) < 2) {
        printf("Unable to parse first line of first file\n");
        return EXIT_FAILURE;
    } 
    ListHndl* theHash = newHash(hashTableSize);
    int libraryID;
    char *tempString = calloc(numDataLines,41*sizeof(char));
    char lineHolder[129];
    //discard the new line which always shows up
    fgets(lineHolder, 128, file);
    for(int i = 0; i < numDataLines; i++) {
        //Gets the whole line to be scanned with sscanf
        fgets(lineHolder, 128, file);

        //If the line consists of just a newline char, continue
        if(strcmp(lineHolder, "\n") == 0 ) {
            continue;
        }
        //Scans the line retrieved from fgets and placed in lineHolder
        if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID,&tempString[i]) == 0){
            printf("Unable to parse line %d of first file\n",i+2);
            return EXIT_FAILURE;
        }
        insert(libraryID, &tempString[i], hashTableSize, theHash);
    }
    char String[41];
    fgets(String, 40, secondFile);
    numDataLines2 = atoi(String);
    char *storeSecondFileStuff = calloc(numDataLines2,41*sizeof(char));
    for(int i = 0; i< numDataLines2; i++) {
        fgets(lineHolder, 128, secondFile);
        if(strcmp(lineHolder, "\n") == 0) {
            continue;
        }
        if(sscanf(lineHolder, "%40[^\n]",&storeSecondFileStuff[i]) == 0) {
            printf("Unable to parse line %d of second file\n",i+2);
            return EXIT_FAILURE;
        }
        lookup(theHash, &storeSecondFileStuff[i], hashTableSize);
    }
    printf("\n");
    fclose(file);
    fclose(secondFile);
    return 0;
}

谢谢!

【问题讨论】:

  • 如果您不尝试讲述有关您的代码的故事,而是实际向我们展示,这对我们所有人来说会容易得多
  • 我放了一个包含我所有代码的链接。需要我详细说明一下吗?
  • 另外:sscce.org
  • 我编辑了一些代码,它无法编译,因为它需要各种文件,感觉太多,无法粘贴到这里,但我认为程序的要点就在那里。

标签: c arrays string hashtable


【解决方案1】:

我认为您有多个问题。首先,您可能没有正确扫描输入行。换行

 if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID,&tempString[i]) == 0)

 if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID, tempString) < 0)

这样,您将捕获sscanf 函数没有成功转换两个参数的情况 - 例如,如果输入行中没有逗号。注意sscanf返回的是成功转换的次数;成功将返回值2,因此测试&lt;2 是正确的方法。

还请注意,我将 &amp;tempString[i] 更改为 tempString。前者指向tempString 沿线的某个地方——它只分配了41 个字符。然而,您始终允许最多 40 个字符(加上 '\0' 写入其中 - 所以您将写入字符串的末尾。由于这只是一个临时变量,这样做没有任何意义。只需扫描输入进入 temp 变量,然后对它做任何你需要做的事情。

这意味着您的insert 也发生了变化,从

    insert(libraryID, &tempString[i], hashTableSize, theHash);

    insert(libraryID, tempString, hashTableSize, theHash);

同样,您需要在代码的底层做同样的事情。

这是使代码为您工作的尝试 - 看看这是否恰到好处。请注意,我真正所做的只是更改了tempStringstoreSecondFileStuff 的类型,并相应地修改了它们在各种函数调用中的使用方式。由于所涉及的其他文件的复杂性,我没有尝试编译/运行 - 但这应该会有所帮助:

int main(int argc, char * argv[]) {

    if (argc != 3) {
        printf("Incorrect arguments, please specify 2 files to be read\n");
        return EXIT_FAILURE;
    }
    FILE *file = fopen( argv[1], "r");
    FILE *secondFile = fopen(argv[2], "r");
    if (file == 0 || secondFile == 0) {
        printf("Could not open a file\n");
        return EXIT_FAILURE;
    }
    int numDataLines2;
    int numDataLines;
    int hashTableSize;
    //First line of first file gives number of lines in file and 
    //size of hash table to be made
    if(fscanf(file, "%d%d", &numDataLines, &hashTableSize) < 2) {
        printf("Unable to parse first line of first file\n");
        return EXIT_FAILURE;
    } 
    ListHndl* theHash = newHash(hashTableSize);
    int libraryID;
    char **tempString = calloc(numDataLines,sizeof(char*));  // <<< ARRAY of pointers
    char lineHolder[129];
    //discard the new line which always shows up
    fgets(lineHolder, 128, file);
    for(int i = 0; i < numDataLines; i++) {
        //Gets the whole line to be scanned with sscanf
        fgets(lineHolder, 128, file);
        tempString[i] = calloc(1, 41 * sizeof(char)); // <<< space for this string
        //If the line consists of just a newline char, continue
        if(strcmp(lineHolder, "\n") == 0 ) {
            continue;
        }
        //Scans the line retrieved from fgets and placed in lineHolder
        if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID, tempString[i]) < 0){ // <<< changed
            printf("Unable to parse line %d of first file\n",i+2);
            return EXIT_FAILURE;
        }
        insert(libraryID, tempString[i], hashTableSize, theHash); // <<< changed
    }
    char String[41];
    fgets(String, 40, secondFile);
    numDataLines2 = atoi(String);
    char **storeSecondFileStuff = calloc(numDataLines2, sizeof(char*)); // changed: again char **
    for(int i = 0; i< numDataLines2; i++) {
        fgets(lineHolder, 128, secondFile);
        storeSecondFileStuff[i] = calloc(1, 41 * sizeof(char));
        if(strcmp(lineHolder, "\n") == 0) {
            continue;
        }
        if(sscanf(lineHolder, "%40[^\n]",storeSecondFileStuff[i]) == 0) {
            printf("Unable to parse line %d of second file\n",i+2);
            return EXIT_FAILURE;
        }
        lookup(theHash, storeSecondFileStuff[i], hashTableSize); // <<<< changed
    }
    printf("\n");
    fclose(file);
    fclose(secondFile);
    return 0;
}

【讨论】:

  • 所以我把它改成了
  • 实际上,我错误地将 ~16 行更改为 if(sscanf(lineHolder, "%40[^\n]",&amp;storeSecondFileStuff[i]) == 0) 并导致错误。我改变了你说的那行,但我没有从中得到任何错误。您正在谈论的那一行以“int,booktitle”的形式以文本形式读取,即12345,奥赛罗。
  • 查看更新的答案。你用相对于你的字符串的偏移量保存数据的方式真的让我很困扰。我很难理解你的意思 - 但无论是什么,你都没有这样做。
  • 我有&amp;tempString[i],因为我将指向该内存的指针传递给存储在我的哈希表中,并且我不希望它被覆盖。我将==0if(sscanf(lineHolder, "%d, %40[^\n]", &amp;libraryID,&amp;tempString[i]) == 0) 更改为`
  • 我发现了我的问题,我有一个search 函数,它使用== 比较存储为void * 变量的两个字符串。我将它们投射到char *,然后使用strcmp,它成功了!谢谢一百万,我真的很感激!
猜你喜欢
  • 1970-01-01
  • 2017-01-06
  • 2017-03-25
  • 2023-01-11
  • 2019-12-23
  • 2020-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多