简体   繁体   中英

Equal strings produces different hash index

I have a program here that does replicate a memory filesystem (not finished yet), it has to read from a file its commands and they are pretty self explanatory here:

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

I then have a function that given the string it manipulates it to insert folder names in an array strings, a command is a command string and the fullPath string is given by another function that does use the previously created array of strings to compose a new one. Here is the struct and the manipulation structure:

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

This is the node structure that does implement the tree-like structure:

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;

And the function that does manipulate the string:

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;
}

I have a createDir function that does check if the node* passed to the function is either a dir or the root (imagine this has a tree); if it is it creates the node.

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;
}

Note that this createDir functions is created with the purpose of creating a direct subDir of the node* fatherOfChildToCreate so basically the first command of the text file does create /foo using this function because its only parentDir is the root one, which is created in the main() . The second command will search for the /foo directory using this function down below, and since it is the parent directory of /foo/bar that pointer will be passed to the createDir function that will create a childNode in the /foo dir.

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;
}

In all this I've used this hash function to search for the parentDir and inserting a new element in the node->childNodes[] array

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;
}

Now, I'll paste the main() which is the last function to review.

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;
}

So, what this does is reading line to line from the file, creating and filling the command struct, it then creates an upPath which is the parent (to be found) and the fullPath. The problem I am getting is that the program uses createDir for the first line of this text file, and this is ok, but reading foo in the comando->path[I] for some strange reason, the hash function gives me 179 which is not correct. The in goes on, the second line it uses linearSearchUpper() to search for the parent folder /foo , so it gives comando->path[I] which is again foo but this time the hashCalc gives me 905 which should be the correct answer so in the end the linearSearchUpper can't find the /foo folder since it doesn't exist in the index 905. This thing happens every time I use a create command or create_dir with folders that are childs of the rootOne, so dirs like /foo, /dir, /bar will give me a strange hash index.

Do you have any idea on why this could happen?

I haven't tried to understand your whole program, but the strings for wich you get the different hashes really are different: One of them retains the new-line character at the end, probably from fgets .

The numerc value of the new-line character in ASCII is 10, so:

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

The solution is to either remove trailing spaces from the string you receive from fgets or to use better tokenising, that will guarantee that your tokens don't have leading or trailing spaces.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM