[英]C - Integer array yielding different values in a for loop
我正在遍歷一個整數數組並嘗試查找非零元素並獲取計數。 這是我的完整代碼。
#include <stdio.h>
#include <stdlib.h>
int countelem(int *a, int a_length){
int i, count = 0;
for (i=0; i<a_length; i++){
if (a[i] != 0) {
printf("element number: %d and element is: %d\n", i, a[i]);
count ++;
};
};
return count;
}
int main(){
int count, a_length = 5;
int *ptr_a, a[a_length];
ptr_a = calloc(a_length, 4);
ptr_a = a;
a[0] = 1;
count = countelem(ptr_a, a_length);
printf("number of non zeroes %d\n", count);
if (ptr_a){
printf("needs to be freed\n");
free(ptr_a);
}
return 0;
}
我正在使用命令進行編譯
cc -Wall -std=c99 con.c -o con
在運行./con
我基本上遇到了兩個問題。
if (a[i] != 0)
a[i] 中的函數 countelem 中,對未初始化的元素產生不相關的結果。ptr_a
分配內存,為什么pointer being freed was not allocated
導致錯誤pointer being freed was not allocated
的調用free(ptr_a)
。這是標准輸出
element number: 0 and element is: 1
element number: 1 and element is: 32767
element number: 2 and element is: 185925632
element number: 3 and element is: 1
number of non zeroes 4
needs to be freed
con(535,0x7ffff180a3c0) malloc: *** error for object 0x7fff54aaefe0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
非常感謝您的幫助。
注意。 我注意到的一件有趣的事情是,如果我使用的是double
數組而不是int
,則a[i]
提供正確的輸出。
嗯……“你在想什么?”
int *ptr_a, a[a_length];
讓我們看兩行,看看我們是否能理解你在做什么:
ptr_a = calloc(a_length, 4);
ptr_a = a;
上面的第 1 行使用calloc
分配了一塊內存,為4-bytes
a_length
成員分配了塊大小,給定a_length = 5;
總共20-bytes
a_length = 5;
. 然后它將新內存塊的起始地址分配給ptr_a
。
上面的第 2 行,然后將數組a
(具有自動存儲類型)的地址分配給ptr_a
覆蓋您剛剛分配的內存塊的內存地址(從而導致內存泄漏,因為沒有更多的引用開始)新塊意味着它永遠不會被釋放)。
但是,由於ptr_a
現在指向以前未使用malloc
、 calloc
或realloc
分配的內存地址,因此當您將ptr_a
傳遞給free (ptr_a);
繁榮! 段錯誤。
使用calloc
分配的內存進行存儲
您根本不需要 VLA(可變長度數組) a
。 您分配一塊足以容納五個整數值的內存塊, ptr_a
該塊的起始地址分配給ptr_a
。 您只需在嘗試使用a
使用ptr_a
,例如
#include <stdio.h>
#include <stdlib.h>
#define NELEMENTS 5 /* if you need a constant, #define one (or more) */
int countelem (int *a, int a_length)
{
int i, count = 0;
for (i = 0; i < a_length; i++)
if (a[i] != 0) {
printf ("element number: %d and element is: %d\n", i, a[i]);
count++;
} /* no ; following block closure */
return count;
}
int main (void) {
int count = 0, /* initialize all variables */
a_length = NELEMENTS,
*ptr_a = NULL;
ptr_a = calloc(a_length, sizeof *ptr_a); /* allocate block of mem */
if (ptr_a == NULL) { /* validate & handle error before using block */
perror ("calloc-ptr_a");
return 1;
}
ptr_a[0] = 1; /* assign value 1 as first value in block of mem */
count = countelem (ptr_a, a_length);
printf ("number of non zeroes %d\n", count);
free(ptr_a); /* you validated the block above, just free */
return 0;
}
示例使用/輸出
$ ./bin/alloccount
element number: 0 and element is: 1
number of non zeroes 1
內存使用/錯誤檢查
在你寫的,可動態分配內存的任何代碼,您有任何關於分配的內存任何塊2個職責:(1)始終保持一個指針的起始地址的存儲器中,以便塊,(2),當它是沒有它可以被釋放不再需要。
您必須使用內存錯誤檢查程序來確保您不會嘗試訪問內存或寫入超出/超出分配塊的邊界,嘗試讀取或基於未初始化值的條件跳轉,最后,確認你釋放了你分配的所有內存。
對於 Linux valgrind
是正常的選擇。 每個平台都有類似的內存檢查器。 它們都易於使用,只需通過它運行您的程序即可。
$ valgrind ./bin/alloccount
==7530== Memcheck, a memory error detector
==7530== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==7530== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==7530== Command: ./bin/alloccount
==7530==
element number: 0 and element is: 1
number of non zeroes 1
==7530==
==7530== HEAP SUMMARY:
==7530== in use at exit: 0 bytes in 0 blocks
==7530== total heap usage: 1 allocs, 1 frees, 20 bytes allocated
==7530==
==7530== All heap blocks were freed -- no leaks are possible
==7530==
==7530== For counts of detected and suppressed errors, rerun with: -v
==7530== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始終確認您已釋放所有分配的內存並且沒有內存錯誤。
使用 VLA 進行存儲
相反,如果您確實想使用 VLA,則無需使用calloc
分配內存。 這是一個或另一個,但不是兩個,命題。
無論存儲是由 VLA 提供還是由calloc
,您仍然可以使用ptr_a
指向該存儲。 但是,如果存儲由 VLA 提供,則不要使用calloc
分配,只需:
int a[a_length], *ptr_a = a;
這就是聲明 VLA 和指向 VLA 的指針所需的全部內容。 (注意:VLA 值是不確定的,所以在使用之前,您可能需要包含string.h
和memset (a, 0, sizeof a);
)
如果您使用可變長度數組作為存儲而不是使用calloc
進行分配,則您的代碼將簡化為:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NELEMENTS 5 /* if you need a constant, #define one (or more) */
int countelem (int *a, int a_length)
{
int i, count = 0;
for (i = 0; i < a_length; i++)
if (a[i] != 0) {
printf ("element number: %d and element is: %d\n", i, a[i]);
count++;
} /* no ; following block closure */
return count;
}
int main (void) {
int count = 0, /* initialize all variables */
a_length = NELEMENTS,
a[a_length], *ptr_a = a;
memset (a, 0, sizeof a); /* initialize a all zero */
ptr_a[0] = 1; /* assign value 1 as first element */
count = countelem (ptr_a, a_length);
printf ("number of non zeroes %d\n", count);
return 0;
}
(注意:如上所述添加memset
。沒有它,任何訪問a[1]
- a[4]
不確定值的嘗試都會導致未定義行為(以及您發現的時髦值輸出))
簡單地刪除a_length
並使用NELEMENTS
代替刪除 VLA 並提供帶有普通數組的存儲,您可以在聲明時對其進行初始化,例如
int count = 0, /* initialize all variables */
a[NELEMENTS] = {0},
*ptr_a = a;
...
count = countelem (ptr_a, NELEMENTS);
(輸出相同,但不需要string.h
或memset
或任何需要通過內存/錯誤檢查運行它)
啟用附加警告(至少-Wextra
)
至少,為 gcc/clang 添加-Wextra
(盡管您還應該另外添加-pedantic -Wshadow
),以便 VS 使用/W3
。 在代碼完全編譯之前不要接受代碼——沒有任何警告。 聽聽你的編譯器告訴你什么,閱讀並理解警告。 它將為您提供找到每個有問題的代碼位的精確行。 在繼續之前先修復它。 簡單地解決所有警告可以並且將會消除大多數問題,您會發現自己花費大量時間解決其他問題。
仔細檢查一下,如果您有任何問題,請告訴我。
您已分配 ptr_a 指向 a,堆棧上的未初始化數組 rhat 可以包含任何隨機值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.