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

value stored in heap changed automatically in c?

提问人:tycoon 提问时间:3/18/2022 最后编辑:tycoon 更新时间:3/21/2022 访问量:143

问:

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

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. 如果 file 包含所有参数,则将该路径添加到另一个变量值。
  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 在执行过程中更改为一些乱码值。在深入挖掘时,我发现变量的值在我运行这个 for 循环时发生了变化paath

    // 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();
    }

为了更清楚。我创建了一个字符串值并创建了另一个指针(结果)数组,该数组将包含字符串不同部分的地址。我通过考虑这个答案来使用这种方法

这是我的终端输出

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)

这里很明显,它可以读取 paath 值,但在 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;
}
c 堆内存

评论

0赞 pmg 3/18/2022
我想你想要某种东西:==> ...完成后,请记住资源。malloc()/strcpy()results[index] = paath;results[index] = malloc(strlen(paath) + 1); strcpy(results[index], paath);free()
1赞 tycoon 3/18/2022
不,我在编译此内容时没有任何警告。当我按照这里有人的建议处理代码时,我总是确保处理警告。
1赞 M Oehm 3/18/2022
你的数组有 10 个元素,但你的循环是针对 20 个元素的数组,所以中途你写越界了,这可能会覆盖其他一些东西。results
1赞 Jabberwocky 3/18/2022
@tycoon 我希望你吸取了教训:不要使用散落在代码中的幻数(如 10 和 20),而是使用类似 .#define NB_ENTRIES 20
1赞 M Oehm 3/18/2022
好吧,它解决了中途发生变化的问题。可能还有其他问题。paath

答:

0赞 tycoon 3/21/2022 #1

我被告知要发布一个答案,而不是在有问题的 [SOLVED] 前面加上前缀,所以我发布了这个答案

此代码中有许多错误,包括一些逻辑错误

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

感谢所有相关评论部分的帮助,我自己不可能弄清楚这一点