c - 相同的字符串产生不同的哈希索引

标签 c string function pointers

我这里有一个程序可以复制内存文件系统(尚未完成),它必须从文件中读取其命令,并且它们在这里非常不言自明:

create /foo
create /foo/bar
create /foo/baz
create /foo/baz/qux
write  /foo/bar "test"
read   /foo/bar
read   /foo/baz/qux
read   /foo/baz/quux
create /foo/bar
create /dir
create /bar
create /dir/bar
find bar
delete /foo/bar
find wat
find foo
read   /foo/bar
create /foo/bar
read   /foo/bar
delete_r /foo
exit
然后,我有一个函数,给定字符串,它操纵它在数组字符串中插入文件夹名称,命令是命令字符串,fullPath 字符串由另一个函数给出,该函数使用之前创建的字符串数组来组成一个新的。这是结构和操作结构:

typedef struct _command {
    unsigned char command[10];
    unsigned char path[255][255];
    unsigned char* fullPath;
    int pathLevels;
} command;

这是实现树状结构的节点结构:

typedef struct _node {
    int isRoot;
    int isDir;
    char* message;
    int childNumber;
    struct _node* childNodes[1024];
    unsigned char fullPath[MAX_LEN_PATH];
    unsigned char resName[255];
} node;

以及操作字符串的函数:

command* createCommandMul(unsigned char* str) {
    unsigned char* c = str;
    command* commandPointer = (command*) malloc(sizeof(command));
    //commandPointer->path[0][0] = '/';
    //commandPointer->path[0][1] = '\0';
    int commandIndex = 0;
    int pathLevel = 0;
    int pathIndex = 0;
    /* Parte Comando */
    while(*c != ' ' && commandIndex < 10) {
        commandPointer->command[commandIndex] = *c++;
        commandIndex++;
    }
    while(commandIndex<10) {
        commandPointer->command[commandIndex] = '\0';
        commandIndex++;
    }
    while(*c == ' ' || *c == '/') c++; 
    /* Parte Path*/
    while(*c != '\0') {
        if (*c == '/') {
            commandPointer->path[pathLevel][pathIndex] = '\0';
            pathLevel++;
            pathIndex = 0;
            c++;
        } else {
            commandPointer->path[pathLevel][pathIndex] = *c++;
            pathIndex++;
        }
    }
    commandPointer->path[pathLevel][pathIndex] = '\0';
    commandPointer->pathLevels = pathLevel;
    return commandPointer;
}

我有一个 createDir 函数,它检查传递给该函数的节点*是否是目录或根(想象它有一棵树); 如果是,则创建节点。

int createDir(node* fatherOfChildToCreate, unsigned char* fullPath, command* currentCommand) {
    if ((fatherOfChildToCreate->isRoot == 1 || fatherOfChildToCreate->isDir == 1) && fatherOfChildToCreate->childNumber < 1024) {
        node* dirToCreate = (node*) malloc(sizeof(node));
        command* comando = (command*) currentCommand;
        dirToCreate->isDir = 1;
        dirToCreate->isRoot = 0;
        dirToCreate->message = NULL;
        dirToCreate->childNumber = 0;
        strcmp(dirToCreate->fullPath, fullPath);
        for (int i = 0; i < 1024; i++) dirToCreate->childNodes[i] = NULL;
        int index = (int) hashCalc(comando->path[comando->pathLevels]);
        printf("Hash di %s = %d", comando->path[comando->pathLevels], index);
        fatherOfChildToCreate->childNodes[index] = dirToCreate;
        fatherOfChildToCreate->childNumber += 1;
        return 1;
    } else return 0;
}

请注意,创建此createDir函数的目的是创建node*fatherOfChildToCreate的直接子目录,因此基本上文本文件的第一个命令确实创建 >/foo 使用此函数,因为它唯一的 parentDir 是根目录,它是在 main() 中创建的。 第二个命令将使用下面的函数搜索 /foo 目录,并且由于它是 /foo/bar 的父目录,因此指针将传递给 createDir函数将在 /foo 目录中创建一个 childNode

node* linearSearchUpper(node* rootNode, unsigned char* upperPath, command* currentCommand) {
    command* comandoSearch = (command*) currentCommand;
    node* curr = (node*) rootNode;
    int counter = comandoSearch->pathLevels;
    int index;
    unsigned char* upperName = comandoSearch->path[comandoSearch->pathLevels - 1];
    for (int i = 0; i < counter; i++) {
        index = (int) hashCalc(comandoSearch->path[i]);
        printf("Hash di %s = %d", comandoSearch->path[i], index);
        if (curr->childNodes[index] == NULL) return NULL;
        else curr = curr->childNodes[index];
    }
    if (strcmp(upperPath, curr->fullPath) == 1) return curr;
}

在这一切中,我使用这个哈希函数来搜索parentDir并在node->childNodes[]数组中插入一个新元素

unsigned long hashCalc(unsigned char* str) {
    unsigned long hash = 5381;
    int c;
    while (c = *str++)
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
    return hash % 1024;
}

现在,我将粘贴 main(),这是要查看的最后一个函数。

int main() {
    node* rootNode = (node*) createRoot();
    command* comando = (command*) malloc(sizeof(command));
    unsigned char* upPath = NULL;
    unsigned char* allPath = NULL;
    unsigned char* line = NULL;
    FILE* fp;
    size_t len = 0;
    ssize_t read;

    fp = fopen("/Users/mattiarighetti/Downloads/semplice.txt", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);
    while ((read = getline(&line, &len, fp)) != -1) {
        if (*line == 'f') {
            //comandoFind = createCommandFind(line);
        } if (*line == 'w') {
            //comandoWrite = createCommandWrite(line);
        } if (*line == 'c') {
            comando = createCommandMul(line);
            upPath = upperPath(comando);
            allPath = fullPath(comando);
            if (comando->pathLevels == 0) {
                if (createDir(rootNode, allPath, comando) == 1) printf("ok\n\n");
                else printf("no\n\n");
            } else {
                node* upperNode = (node*) linearSearchUpper(rootNode, upPath, comando);
                if (upperNode == NULL) {
                    printf("no\n\n");
                }
                else {
                    if (createDir(upperNode, allPath, comando) == 1) printf("ok\n\n");
                    else printf("no\n\n");
                }
            }
        }
    }
    fclose(fp);
    if (line)
        free(line);
    return 0;
}

因此,它的作用是从文件中逐行读取,创建并填充命令结构,然后创建一个 upPath,它是父级(要找到的)和 fullPath。我遇到的问题是程序使用 createDir 作为该文本文件的第一行,这是可以的,但是在 comando->path[I] 中读取 foo > 由于某些奇怪的原因,哈希函数给了我 179,这是不正确的。接下来,第二行使用 LinearSearchUpper() 来搜索父文件夹/foo ,因此它给出了 comando->path[I] ,这又是 foo 但这次 hashCalc 给了我 905 这应该是正确的答案,所以最终 LinearSearchUpper 找不到/foo 文件夹,因为它不存在于索引 905 中。这种情况每次都会发生当我使用 create 命令或 create_dir 来处理 rootOne 的子文件夹时,像/foo、/dir、/bar 这样的目录会给我一个奇怪的哈希索引。

您知道为什么会发生这种情况吗?

最佳答案

我没有尝试理解你的整个程序,但是你得到不同哈希值的字符串确实是不同的:其中一个在末尾保留换行符,可能来自fgets.

换行符的 ASCII 值是 10,所以:

hash("foo") == 905;
hash("foo\n") == (33 * hash("foo") + '\n') % 1024
              == (33 * 905 + 10) % 1024
              == 179

解决方案是从从 fgets 收到的字符串中删除尾随空格,或者使用更好的标记化,这将保证您的标记没有前导或尾随空格。

关于c - 相同的字符串产生不同的哈希索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46130328/

相关文章:

java - 在 hibernate 中保留对象时无法将枚举转换为字符串

c# - 在 C# 中拆分字符串

c - 以标准格式打印名称

function - 在 F# 中,是否可以检查两个值是否具有相同的构造函数?

python - Pandas 方法在整个 DataFrame 上应用函数

从命名管道并发选择

c - 获取一个字符串并在c中提取2个子字符串

java - 服务器套接字松散绑定(bind)

c++ - c/c++编译时 "compatibility"检查

将多个列表中的唯一值合并到一个列表的Python函数