提问人:tycoon 提问时间:3/18/2022 最后编辑:tycoon 更新时间:3/21/2022 访问量:143
存储在堆中的值在 C 中自动更改?
value stored in heap changed automatically in c?
问:
我正在从书本上学习 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.
我编写了一个程序来做到这一点(至少尝试实现这一点)。
- 读取文件 ~/.logfind
- 获取 ~/.logfind 指定的路径并开始读取该文件(即 /home/noobgrammer/scripts/power.sh)
- 从文件中读取每个单词,并将其与传递的参数进行匹配
- 如果 file 包含所有参数,则将该路径添加到另一个变量值。
- 读取所有文件后,打印保存在值中的路径。
可能我的代码会伤害你的大脑(逻辑和编码风格)很抱歉,我还在学习:-)
如果您看到一些函数,例如 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;
}
答:
我被告知要发布一个答案,而不是在有问题的 [SOLVED] 前面加上前缀,所以我发布了这个答案
此代码中有许多错误,包括一些逻辑错误
- 正如注释中所建议的,结果数组有 10 个元素,但循环运行 20 次。因此,在更新的代码中,我将值更改为 10。同样,正如注释中建议的那样,应该使用宏来定义一个值,该值在程序过程中将保持不变。这种方法几乎没有什么优点 - 如果你必须更改数组大小,你不必到处更改值,只需更改宏的值就可以了。
- 在非工作代码中:在函数中,我创建了一个大字符串,如果文件中存在任何传递的参数,它将保存文件的路径,它会在文件中添加该路径。但是对于我正在阅读的每个文件,我都会一次又一次地调用read_file,这会导致一次又一次地声明值。因此,在函数变量的每次调用被破坏后,存储在其中的值也会被破坏(从技术上讲,不是破坏,而是为每个调用分配新的内存,这也表明程序中存在内存泄漏)。所以我不得不在函数中移动它。
read_file
values
values
values
path
- 在功能上:我有一个任务。因此,通过这样做,我不会将字符串保存在(由 result[index]) 指出)中。我正在保存 paath 变量给出的地址,而不是其中的值。因此,对于每个匹配值,结果都是保存 paath 变量指向的地址。因此,结果将一次又一次地具有相同的地址。所以教训是,如果你试图在堆中保存一个字符串,请使用strcpy或类似的函数,避免使用=(赋值运算符)
read_file
result[index] = paath
values
- 现在的逻辑错误是:目标是在 logfind 指向的文件中搜索所有参数。但我的程序没有这样做。虽然它与 OR 标志 (-o/-O) 一起工作,但如果没有 OR 标志,它不会给出正确的结果。因为它考虑到传递的任何参数都将在文件中存在一次。因此,它将打印一个带有礼物 3 次的文件。避免这种情况的更好方法是在文件的一次迭代中仅搜索单个参数。不要在单次迭代中比较每个参数。
./logfind if and or
if
感谢所有相关评论部分的帮助,我自己不可能弄清楚这一点
评论
malloc()/strcpy()
results[index] = paath;
results[index] = malloc(strlen(paath) + 1); strcpy(results[index], paath);
free()
results
#define NB_ENTRIES 20
paath