存储在堆中的值在 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.
我写了一个程序来做这个(至少尝试实现这个)。
- 读取文件~/.logfind
- 采用 ~/.logfind 指定的路径并开始读取该文件(即 /home/noobgrammer/scripts/power.sh)
- 从文件中读取每个单词并将其与传递的参数进行匹配
- 如果文件包含所有参数,则将该路径添加到另一个变量值。
- 并在读取所有文件后打印值中保存的路径。
可能我的代码会伤害你的大脑(逻辑和编码风格)所以很抱歉,我还在学习:-)
如果你看到一些函数比如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 这个答案
这段代码有很多错误,包括一些逻辑错误
- 正如评论中所建议的,结果数组有 10 个元素,但循环 运行 20 次。因此,在更新后的代码中,我将该值更改为 10。再次如评论中所建议的那样,应该使用宏来定义一个值,该值将在程序运行期间保持不变。这种方法有几个优点 - 如果您必须更改数组大小,则不必更改所有位置的值,只需更改宏的值即可。
- 在 non-working 代码中:在函数
read_file
中我创建了一个大字符串 values
如果文件中存在任何传递的参数,它将保存文件的路径它将在文件中添加该路径。但是对于我正在阅读的每个文件,我都会一次又一次地调用 read_file,这会导致一次又一次地声明值。因此,在每次调用函数变量 values
后,存储在其中的值也会被破坏(技术上不是破坏,而是为每次调用分配新内存,这也表明 程序中存在内存泄漏).所以我不得不在函数 path
. 中移动 values
- 在函数
read_file
中:我有一个作业 result[index] = paath
。因此,通过这样做,我不会将字符串保存在 values
(由结果 [index] 指向) 中。我正在保存 paath 变量给出的地址而不是其中的值。因此,对于每个匹配值,结果都会保存 paath 变量指向的地址。因此结果将一次又一次地具有相同的地址。所以教训是如果你试图在堆中保存一个字符串使用strcpy或类似的函数,避免使用=(赋值运算符)
- 现在是逻辑错误:目标是搜索 logfind 指向的文件中的所有参数。但是我的程序没有这样做。尽管使用 OR 标志 (-o/-O) 也能正常工作,但如果没有 OR 标志,它不会给出正确的结果。因为它正在考虑传递的任何参数都将在文件中出现一次。所以对于
./logfind if and or
它将打印一个文件 if
出现 3 次。避免这种情况的更好方法是在文件的一次迭代期间仅搜索单个参数。不要在单次迭代中比较每个参数。
感谢有问题的评论部分的每个人帮助我,我自己不可能解决这个问题
我正在从 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.
我写了一个程序来做这个(至少尝试实现这个)。
- 读取文件~/.logfind
- 采用 ~/.logfind 指定的路径并开始读取该文件(即 /home/noobgrammer/scripts/power.sh)
- 从文件中读取每个单词并将其与传递的参数进行匹配
- 如果文件包含所有参数,则将该路径添加到另一个变量值。
- 并在读取所有文件后打印值中保存的路径。
可能我的代码会伤害你的大脑(逻辑和编码风格)所以很抱歉,我还在学习:-)
如果你看到一些函数比如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 这个答案
这段代码有很多错误,包括一些逻辑错误
- 正如评论中所建议的,结果数组有 10 个元素,但循环 运行 20 次。因此,在更新后的代码中,我将该值更改为 10。再次如评论中所建议的那样,应该使用宏来定义一个值,该值将在程序运行期间保持不变。这种方法有几个优点 - 如果您必须更改数组大小,则不必更改所有位置的值,只需更改宏的值即可。
- 在 non-working 代码中:在函数
read_file
中我创建了一个大字符串values
如果文件中存在任何传递的参数,它将保存文件的路径它将在文件中添加该路径。但是对于我正在阅读的每个文件,我都会一次又一次地调用 read_file,这会导致一次又一次地声明值。因此,在每次调用函数变量values
后,存储在其中的值也会被破坏(技术上不是破坏,而是为每次调用分配新内存,这也表明 程序中存在内存泄漏).所以我不得不在函数path
. 中移动 - 在函数
read_file
中:我有一个作业result[index] = paath
。因此,通过这样做,我不会将字符串保存在values
(由结果 [index] 指向) 中。我正在保存 paath 变量给出的地址而不是其中的值。因此,对于每个匹配值,结果都会保存 paath 变量指向的地址。因此结果将一次又一次地具有相同的地址。所以教训是如果你试图在堆中保存一个字符串使用strcpy或类似的函数,避免使用=(赋值运算符) - 现在是逻辑错误:目标是搜索 logfind 指向的文件中的所有参数。但是我的程序没有这样做。尽管使用 OR 标志 (-o/-O) 也能正常工作,但如果没有 OR 标志,它不会给出正确的结果。因为它正在考虑传递的任何参数都将在文件中出现一次。所以对于
./logfind if and or
它将打印一个文件if
出现 3 次。避免这种情况的更好方法是在文件的一次迭代期间仅搜索单个参数。不要在单次迭代中比较每个参数。
values
感谢有问题的评论部分的每个人帮助我,我自己不可能解决这个问题