存储在堆中的值在 c 中自动更改?

value stored in heap changed automatically in c?

我正在从 Learn C the hard Way 书中学习 C。我正在做一个 logfind 练习,据此我需要创建一个需要一些参数的程序。它将读取一个文件(.logfind),该文件将具有指向其他一些文件的路径。该程序将简单地搜索在 ~./logfind 中给出的文件中传递的参数。这是作者的解释

1. This tool takes any sequence of words and assumes I mean “and” for them. So "logfind zedshaw smart guy" will find all files that have zedshaw and smart and guy in them.
2. It takes an optional argument of -o if the parameters are meant to be or logic.
3. It loads the list of allowed log files from ~/.logfind.
4. The list of file names can be anything that the glob function allows. Refer to man 3 glob to see how this works. I suggest starting with just a flat list of exact files, and then add glob functionality.
5. You should output the matching lines as you scan, and try to match them
as fast as possible.

我写了一个程序来做这个(至少尝试实现这个)。

  1. 读取文件~/.logfind
  2. 采用 ~/.logfind 指定的路径并开始读取该文件(即 /home/noobgrammer/scripts/power.sh)
  3. 从文件中读取每个单词并将其与传递的参数进行匹配
  4. 如果文件包含所有参数,则将该路径添加到另一个变量值。
  5. 并在读取所有文件后打印值中保存的路径。

可能我的代码会伤害你的大脑(逻辑和编码风格)所以很抱歉,我还在学习:-)

如果你看到一些函数比如check,或者check_mem这些只是一些宏,定义在dbg.h

代码中会有一些不应该出现的行,但那是因为我试图理解问题所在,所以代码清理得太多并不简单


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

#define LENGTH 200

int toggle = 0;
int count = 1;
int twist = 0;

int usage(void){
    FILE *file = fopen("./.usage", "r");
    check(file, "Opening .usage failed");

    char *buffer = malloc(100 * sizeof(char));
    check_mem(buffer);

    system("clear");
    while (fgets(buffer, 99, file) != NULL) fputs(buffer, stdout);
    fclose(file);

    return 0;

error:
    free(buffer);
    return -1;
}

int compare(char *word, int argc, char *argv[]){

    for (int i = 1 + toggle; i < argc; i++){
        // for or case
        if (strcmp(word, argv[i]) == 0) {
            count += 1;
            if (toggle == 1 || count == argc){
                count = 1;
                return 0;
            } 
        }
    }

    return -1;
}

int read_file(char **results, char *paath, char *sequence[], int argc){
    FILE *file = fopen(paath, "r");
    check(file, "Failed to open %s. Make sure there is a file with that name at right location", paath);

    char *word = malloc(20 * sizeof(char));
    check_mem(word);

    char *values = malloc(LENGTH*20*sizeof(char));
    check_mem(values);

    // pointing all the elements of the results array to values
    for (int i = 0; i < 20; i++){
        results[i] = values + LENGTH*i;
        printf("i %d : %s", i, paath);
        getchar();
    }
    puts("Kill it");

    static int index = 0;

    while(fscanf(file, "%s", word) != EOF){
        if (compare(word, argc, sequence) == 0){
            results[index] = paath;
            twist += 1;
            index += 1;
        }
    }
    
    fclose(file);
    return 0;
error:
    return -1;
}

int path(char *sequence[], int argc){
    FILE *file = fopen("/home/noobgrammer/.logfind", "r");
    check(file, "Opening ~/.logfind failed. Make sure you have a file there");

    char **results = malloc(10 * sizeof(char *));
    check_mem(results);

    char *paath = malloc(LENGTH * sizeof(char));
    check_mem(paath);

    while (fgets(paath, 99, file) != NULL){
        paath[strcspn(paath, "\n")] = 0;
        read_file(results, paath, sequence, argc);
    }

    for (int i = 0; i < twist; i++){
        printf("%s\n", results[i]);
    }


    fclose(file);

    return 0;

error:
    free(results);
    free(paath);

    return -1;
}

int main(int argc, char *argv[]){
    if (argc == 1 || strcmp(argv[1], "-h") == 0) return usage();
    if (strcmp(argv[1], "-o") == 0 || strcmp(argv[1], "-O")==0) toggle = 1;
    if (path(argv, argc) == -1) goto error;

    return 0;
error:
    return -1;
}

这是我的 ~/.logfind 文件

/home/noobgrammer/scripts/power.sh
/home/noobgrammer/makefile/dwm/dwm.c
/home/noobgrammer/scripts/mic_mute.sh

虽然 运行 代码出现错误,文件不存在于给定位置。但是文件存在。然后我 运行 调试器中的代码,发现代码按预期工作,但变量 paath 在执行期间更改为一些乱码值。在挖掘更多时,我发现 paath 变量的值在我 运行 这个 for 循环

时发生了变化
    // pointing all the elements of the results array to values
    for (int i = 0; i < 20; i++){
        results[i] = values + LENGTH*i;
        printf("i %d : %s", i, paath);
        getchar();
    }

为了更清楚。我创建了一个字符串值并创建了另一个指针数组(结果),它将包含字符串不同部分的地址。我通过考虑 this answer

使用这种方法

这是我的终端输出

i 0 : /home/noobgrammer/scripts/power.sh
i 1 : /home/noobgrammer/scripts/power.sh
i 2 : /home/noobgrammer/scripts/power.sh
i 3 : /home/noobgrammer/scripts/power.sh
i 4 : /home/noobgrammer/scripts/power.sh
i 5 : /home/noobgrammer/scripts/power.sh
i 6 : /home/noobgrammer/scripts/power.sh
i 7 : /home/noobgrammer/scripts/power.sh
i 8 : /home/noobgrammer/scripts/power.sh
i 9 : /home/noobgrammer/scripts/power.sh
i 10 : /home/noobgrammer/scripts/power.sh
i 11 : /home/noobgrammer/scripts/power.sh
i 12 :  �V
i 13 :  �V
i 14 :  �V
i 15 :  �V
i 16 :  �V
i 17 :  �V
i 18 :  �V
i 19 :  �V
Kill it
i 0 : /home/noobgrammer/makefile/dwm/dwm.c
i 1 : /home/noobgrammer/makefile/dwm/dwm.c
i 2 : /home/noobgrammer/makefile/dwm/dwm.c
i 3 : /home/noobgrammer/makefile/dwm/dwm.c
i 4 : /home/noobgrammer/makefile/dwm/dwm.c
i 5 : /home/noobgrammer/makefile/dwm/dwm.c
i 6 : /home/noobgrammer/makefile/dwm/dwm.c
i 7 : /home/noobgrammer/makefile/dwm/dwm.c
i 8 : /home/noobgrammer/makefile/dwm/dwm.c
i 9 : /home/noobgrammer/makefile/dwm/dwm.c
i 10 : /home/noobgrammer/makefile/dwm/dwm.c
i 11 : /home/noobgrammer/makefile/dwm/dwm.c
i 12 :  �V
i 13 :  �V
i 14 :  �V
i 15 :  �V
i 16 :  �V
i 17 :  �V
i 18 :  �V
i 19 :  �V
Kill it
[ERROR] (ex26.c:50: errno: No such file or directory) Failed to open �V. Make sure there is a file with that name at right location
ange
�V
�V
�V
�V
�V
�V
�V
�V
�V
�V
�V
Segmentation fault (core dumped)

这里很明显,它可以读取路径值,但在 for 循环期间它正在改变某些地方。我认为这可能是由于内存重叠。我通过添加此行 printf("add. of paath %p, add. of values[i] %p.\n", paath, values[i*LENGTH] ); 检查了两个值的地址,但事实并非如此,我想如果内存重叠发生在堆中,那将是愚蠢的。 所以现在我不知道是什么原因造成的,也不知道为什么会这样。

我更新后的代码(工作正常)

// logfind

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

#define LENGTH 200

int toggle = 0;
int count = 1;
int twist = 0;

int usage(void){
    FILE *file = fopen("./.usage", "r");
    check(file, "Opening .usage failed");

    char *buffer = malloc(100 * sizeof(char));
    check_mem(buffer);

    system("clear");
    while (fgets(buffer, 99, file) != NULL) fputs(buffer, stdout);
    free(buffer);
    fclose(file);

    return 0;

error:
    free(buffer);
    return -1;
}

int compare(char *word, int argc, char *argv[]){

    for (int i = 1 + toggle; i < argc; i++){
        // for or case
        if (strcmp(word, argv[i]) == 0) {
            // there will be problem if an argument comes more than one time because it will
            // contribute to count and thus creating a problem
            count += 1;
            if (toggle == 1 || count == argc){
                count = 1;
                return 0;
            } 
        }
    }

    return -1;
}

int read_file(char **results, char *paath, char *values, char *sequence[], int argc){
    FILE *file = fopen(paath, "r");
    debug("File Opened: %s", paath);
    check(file, "Failed to open %s. Make sure there is a file with that name at right location", paath);

    char *word = malloc(20 * sizeof(char));
    check_mem(word);


    static int index = 0;

    while(fscanf(file, "%s", word) != EOF){
        if (compare(word, argc, sequence) == 0){
//            results[index] = paath;
            debug("Assigning results[%i]: %s", index, paath);
            strcpy(results[index], paath);
            twist += 1;
            index += 1;
            break;
        }
    }
    free(word);

//    if (file) fclose(file);
    return 0;
error:
    return -1;
}

int path(char *sequence[], int argc){
    FILE *file = fopen("/home/bhavuksharma2202/.logfind", "r");
    check(file, "Opening ~/.logfind failed. Make sure you have a file there");

    char **results = malloc(10 * sizeof(char *));
    check_mem(results);

    char *paath = malloc(LENGTH * sizeof(char));
    check_mem(paath);

    char *values = malloc(LENGTH*10*sizeof(char));
    check_mem(values);

    // pointing all the elements of the results array to values
    for (int i = 0; i < 10; i++){
        results[i] = values + LENGTH*i;
    }

    while (fgets(paath, 99, file) != NULL){
        paath[strcspn(paath, "\n")] = 0;
        read_file(results, paath, values, sequence, argc);
    }

    for (int i = 0; i < twist; i++){
        printf("%s\n", results[i]);
    }


    fclose(file);

    return 0;

error:
    free(results);
    free(paath);

    return -1;
}

int main(int argc, char *argv[]){
    if (argc == 1 || strcmp(argv[1], "-h") == 0) return usage();
    if (strcmp(argv[1], "-o") == 0 || strcmp(argv[1], "-O")==0) toggle = 1;
    if (path(argv, argc) == -1) goto error;

    return 0;
error:
    return -1;
}

我被告知 post 一个答案而不是前缀 [SOLVED] 有问题,所以我 post 这个答案

这段代码有很多错误,包括一些逻辑错误

  1. 正如评论中所建议的,结果数组有 10 个元素,但循环 运行 20 次。因此,在更新后的代码中,我将该值更改为 10。再次如评论中所建议的那样,应该使用宏来定义一个值,该值将在程序运行期间保持不变。这种方法有几个优点 - 如果您必须更改数组大小,则不必更改所有位置的值,只需更改宏的值即可。
  2. 在 non-working 代码中:在函数 read_file 中我创建了一个大字符串 values 如果文件中存在任何传递的参数,它将保存文件的路径它将在文件中添加该路径。但是对于我正在阅读的每个文件,我都会一次又一次地调用 read_file,这会导致一次又一次地声明值。因此,在每次调用函数变量 values 后,存储在其中的值也会被破坏(技术上不是破坏,而是为每次调用分配新内存,这也表明 程序中存在内存泄漏).所以我不得不在函数 path.
  3. 中移动 values
  4. 在函数 read_file 中:我有一个作业 result[index] = paath。因此,通过这样做,我不会将字符串保存在 values (由结果 [index] 指向) 中。我正在保存 paath 变量给出的地址而不是其中的值。因此,对于每个匹配值,结果都会保存 paath 变量指向的地址。因此结果将一次又一次地具有相同的地址。所以教训是如果你试图在堆中保存一个字符串使用strcpy或类似的函数,避免使用=(赋值运算符)
  5. 现在是逻辑错误:目标是搜索 logfind 指向的文件中的所有参数。但是我的程序没有这样做。尽管使用 OR 标志 (-o/-O) 也能正常工作,但如果没有 OR 标志,它不会给出正确的结果。因为它正在考虑传递的任何参数都将在文件中出现一次。所以对于 ./logfind if and or 它将打印一个文件 if 出现 3 次。避免这种情况的更好方法是在文件的一次迭代期间仅搜索单个参数。不要在单次迭代中比较每个参数。

感谢有问题的评论部分的每个人帮助我,我自己不可能解决这个问题