我是 C 新手。最近,我试图制作一些函数,使我能够与动态分配的数组进行交互。我并不认为我编写的函数是好的,但它确实有效。我尝试使用
valgrind --tool=memcheck --leak-check=yes ./program
检查我的代码是否存在内存泄漏,运行后它给了我很多 条件跳转或移动取决于单位化值。我尝试运行 valgrind --track-origins=yes ./program
但由于我不太擅长代码,所以我并没有真正得到一些东西。顺便说一句,我使用 Debian WSL(如果有的话)。我只是想确切地知道那是什么以及为什么会发生这个“错误”,因为我想避免任何会破坏我的程序未来假设性能的事情。
提前致谢!
程序.c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct array {
int* data;
int items;
int capacity;
int space;
};
void removeArr(struct array *arr, int index);
void sortArr(struct array *arr, bool reverse);
void printArr(struct array *arr, int limit);
void appendArr(struct array *arr, int item);
void insertArr(struct array *arr, int index, int item);
int main() {
struct array a1;
int i = 0;
a1.items = 0;
a1.capacity = 10;
a1.space = 5;
a1.data = (int*)malloc(a1.capacity * sizeof(int));
if(NULL == a1.data) {
printf("Allocation for a1.data failed\n");
return 1;
}
// Filling up the array with 5 elements
for(i = 0; i < a1.capacity - 5; i++) {
a1.data[i] = i + 1;
a1.items++;
}
// Testing appending, inserting and removing from an array
appendArr(&a1, 6);
appendArr(&a1, 7);
insertArr(&a1, 1, 10);
insertArr(&a1, a1.items, 3);
removeArr(&a1, a1.items - 1);
printf("Before For Loop: %d %d\n", a1.capacity, a1.items);
printArr(&a1, 5);
// Testing appending inside the for loop
for(i = 0; i < 2; i++) appendArr(&a1, i + 15);
printf("After For Loop: %d %d\n", a1.capacity, a1.items);
printArr(&a1, 5);
// Testing insert func when there's no free space in the array
insertArr(&a1, 1, 100);
printf("After insert with extra space: %d %d\n", a1.capacity, a1.items);
printArr(&a1, 5);
// Testing reverse (bubble) sort
putchar('\n');
sortArr(&a1, true);
printArr(&a1, 5);
// Testing standard (bubble) sort
putchar('\n');
sortArr(&a1, false);
printArr(&a1, 5);
// Overwriting the entire array
putchar('\n');
for(i = 0; i < a1.capacity; i++) {
a1.data[i] = i + 1;
}
a1.items = a1.capacity;
// Testing inserting inside the for loop
for(i = 1; i <= 15; i++) {
insertArr(&a1, i, i);
}
putchar('\n');
printArr(&a1, 5);
// Check the curren capacity and items amount after all of the operations with the array
printf("After Insert For Loop: %d %d\n", a1.capacity, a1.items);
// Freeing the dynamically allocated array
free(a1.data);
a1.data = NULL;
return 0;
}
void removeArr(struct array *arr, int index) {
if(0 >= index || index >= arr->capacity) {
printf("ERROR: Index is incorrect\n");
exit(1);
}
for(int i = index; i < arr->capacity; i++) {
if(0 == arr->data[i - 1] && 0 == arr->data[i]) {
continue;
}
arr->data[i - 1] = arr->data[i];
}
arr->data[arr->capacity - 1] = 0;
arr->items--;
}
void sortArr(struct array *arr, bool reverse) {
int i = 0;
bool swapped;
if(false == reverse) {
do {
swapped = false;
for(int j = 0; j < (arr->capacity - 1 - i); j++) {
if(arr->data[j + 1] < arr->data[j]) {
int temp = arr->data[j];
arr->data[j] = arr->data[j + 1];
arr->data[j + 1] = temp;
swapped = true;
}
}
i++;
}
while(swapped)
;
}
if(true == reverse) {
do {
swapped = false;
for(int j = 0; j < (arr->capacity - 1 - i); j++) {
if(arr->data[j + 1] > arr->data[j]) {
int temp = arr->data[j];
arr->data[j] = arr->data[j + 1];
arr->data[j + 1] = temp;
swapped = true;
}
}
i++;
}
while(swapped)
;
}
}
void printArr(struct array *arr, int limit) {
int pos = 0;
for(int i = 0; i < arr->capacity; i++) {
if(pos < limit) {
printf("%d ", arr->data[i]);
pos++;
}
else {
putchar('\n');
printf("%d ", arr->data[i]);
pos = 1;
}
}
putchar('\n');
}
void appendArr(struct array *arr, int item) {
if(arr->items == arr->capacity) {
arr->capacity += arr->space;
arr->data = (int*)realloc(arr->data, arr->capacity * sizeof(int));
if(NULL == arr->data) {
printf("Reallocation for arr->data failed while appending.\n");
exit(1);
}
}
arr->data[arr->items] = item;
arr->items++;
}
void insertArr(struct array *arr, int index, int item) {
if(0 >= index || index >= arr->capacity) {
printf("ERROR: Index is incorrect\n");
exit(1);
}
if(index == arr->items) {
appendArr(arr, item);
}
else if(index > 0 && index < arr->capacity) {
if(arr->items == arr->capacity) {
arr->capacity += arr->space;
arr->data = (int*)realloc(arr->data, arr->capacity * sizeof(int));
if(NULL == arr->data) {
printf("Reallocation for arr->data failed when inserting.\n");
exit(1);
}
}
for(int i = arr->capacity - 1; i >= index; i--) {
if(0 == arr->data[i] && 0 == arr->data[i - 1])
continue;
arr->data[i] = arr->data[i - 1];
}
arr->data[index - 1] = item;
arr->items++;
}
else {
printf("Unexpected error occured while insertion.\n");
exit(2);
}
}
valgrind --tool=memcheck --leak-check=yes ./program
输出:
==14958== Memcheck, a memory error detector
==14958== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==14958== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==14958== Command: ./dev/test
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x1099BA: insertArr (test.c:192)
==14958== by 0x109265: main (test.c:40)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x1099D8: insertArr (test.c:192)
==14958== by 0x109265: main (test.c:40)
==14958==
Before For Loop: 10 8
10 1 2 3 4 5
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x109786: printArr (test.c:147)
==14958== by 0x1092BC: main (test.c:44)
==14958==
==14958== Use of uninitialised value of size 8
==14958== at 0x48ACAAB: _itoa_word (_itoa.c:177)
==14958== by 0x48B7E58: __vfprintf_internal (vfprintf-process-arg.c:164)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x109786: printArr (test.c:147)
==14958== by 0x1092BC: main (test.c:44)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48ACABC: _itoa_word (_itoa.c:177)
==14958== by 0x48B7E58: __vfprintf_internal (vfprintf-process-arg.c:164)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x109786: printArr (test.c:147)
==14958== by 0x1092BC: main (test.c:44)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x109786: printArr (test.c:147)
==14958== by 0x1092BC: main (test.c:44)
==14958==
6 3 0 0
After For Loop: 10 10
10 1 2 3 4 5
6 3 15 16
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x1099BA: insertArr (test.c:192)
==14958== by 0x109326: main (test.c:52)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x1099D8: insertArr (test.c:192)
==14958== by 0x109326: main (test.c:52)
==14958==
After insert with extra space: 15 11
100 10 1 2 3 4
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x109786: printArr (test.c:147)
==14958== by 0x109353: main (test.c:54)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x109786: printArr (test.c:147)
==14958== by 0x109353: main (test.c:54)
==14958==
5 6 3 15 16 0
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x1097C2: printArr (test.c:152)
==14958== by 0x109353: main (test.c:54)
==14958==
==14958== Use of uninitialised value of size 8
==14958== at 0x48ACAAB: _itoa_word (_itoa.c:177)
==14958== by 0x48B7E58: __vfprintf_internal (vfprintf-process-arg.c:164)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x1097C2: printArr (test.c:152)
==14958== by 0x109353: main (test.c:54)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48ACABC: _itoa_word (_itoa.c:177)
==14958== by 0x48B7E58: __vfprintf_internal (vfprintf-process-arg.c:164)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x1097C2: printArr (test.c:152)
==14958== by 0x109353: main (test.c:54)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x1097C2: printArr (test.c:152)
==14958== by 0x109353: main (test.c:54)
==14958==
0 0 0
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x10969C: sortArr (test.c:129)
==14958== by 0x10936E: main (test.c:58)
==14958==
100 16 15 10 6 5
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x109786: printArr (test.c:147)
==14958== by 0x10937F: main (test.c:59)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x109786: printArr (test.c:147)
==14958== by 0x10937F: main (test.c:59)
==14958==
4 3 3 2 1 0
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x1097C2: printArr (test.c:152)
==14958== by 0x10937F: main (test.c:59)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x1097C2: printArr (test.c:152)
==14958== by 0x10937F: main (test.c:59)
==14958==
0 0 0
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x1095BB: sortArr (test.c:112)
==14958== by 0x10939A: main (test.c:63)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B8027: __vfprintf_internal (vfprintf-process-arg.c:58)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x109786: printArr (test.c:147)
==14958== by 0x1093AB: main (test.c:64)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x48B86F6: __vfprintf_internal (vfprintf-process-arg.c:174)
==14958== by 0x48AD65A: printf (printf.c:33)
==14958== by 0x109786: printArr (test.c:147)
==14958== by 0x1093AB: main (test.c:64)
==14958==
0 0 0 0 1 2
3 3 4 5 6 10
15 16 100
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x1099BA: insertArr (test.c:192)
==14958== by 0x109406: main (test.c:75)
==14958==
==14958== Conditional jump or move depends on uninitialised value(s)
==14958== at 0x1099D8: insertArr (test.c:192)
==14958== by 0x109406: main (test.c:75)
==14958==
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 1 2 3
4 5 6 7 8 9
10 11 12 13 14 15
After Insert For Loop: 30 30
==14958==
==14958== HEAP SUMMARY:
==14958== in use at exit: 0 bytes in 0 blocks
==14958== total heap usage: 6 allocs, 6 frees, 1,424 bytes allocated
==14958==
==14958== All heap blocks were freed -- no leaks are possible
==14958==
==14958== Use --track-origins=yes to see where uninitialised values come from
==14958== For lists of detected and suppressed errors, rerun with: -s
==14958== ERROR SUMMARY: 198 errors from 24 contexts (suppressed: 0 from 0)
我试图研究这个确切的问题,但我没有得到任何东西。而且其他人在回答中所说的话也并不是我真正想要的。他们的代码和答案“没有引起我的共鸣”(我什么都不懂,兄弟)。
问题是你读取了
malloc
/realloc
之后还没有初始化的内存。这是因为您在循环中使用 arr->capacity
而不是 arr->items
(分配块中初始化的条目数)。
valgrind注意到的第一个地方是在插入点之后将数据向上推送的循环中。只需切换到 arr->items
而不是
arr->capacity
:
void insertArr(struct array *arr, int index, int item) {
//
for(int i = arr->items; i >= index; i--) { // not arr->capacity
arr->data[i] = arr->data[i - 1];
}
//
}
您在printArr
中也有同样的问题:
void printArr(struct array *arr, int limit) {
//
for(int i = 0; i < arr->items; i++) { // not arr->capacity
//
}
两次sortArr
:
void sortArr(struct array *arr, bool reverse) {
//
for(int j = 0; j < (arr->items - 1 - i); j++) { // not arr->capacity
//
}