[英]Dynamic memory allocation in arrays in C
我花了最后幾個小時嘗試調試代碼,但未能成功。 我認為問題出在我沒有完全了解動態內存分配,但是我也可能犯其他一些錯誤。 這里的問題更多是個人問題,如果有人發現此問題不符合“使之與他人相關”,那么我感到抱歉。
我得到了下一個建議:
從0到100的間隔中的n
隨機元素中創建一個數組A[]
。 創建一個拆分兩個數組的函數,例如:數組B[]
包含> 50
元素,而C[]
包含其余的元素。 使用動態內存分配創建數組A和B。 該函數的參數必須是所有三個數組及其各自的長度。
#include <stdio.h>
#include <stdlib.h>
void Array(int *A, int *nA, int *B, int *nB, int *C, int*nC){
int i;
int nB1 = 0;
int nC1 = 0;
int *tmpB;
int *tmpC;
B = malloc((nB1+1)*sizeof(int));
C = malloc((nC1+1)*sizeof(int));
printf("\n");
for(i = 0 ; i < nA ; i++){
if(A[i] <= 50){
C[i] = A[i];
nC1++;
// The idea here is to have a new array with basically
// no length so that each time one element passes to either
// B or A array that array gets increased at the same
// time as nC or nB
tmpC = realloc(C, sizeof(int) * nC1);
if(tmpC == NULL){
printf("ERROR: realloc failed.\n");
}
C = tmpC;
// C = realloc(C, nC1 + 1);
}
else{
B[i] = A[i];
nB1++;
tmpB = realloc(B, sizeof(int) * nB1);
if(tmpB == NULL){
printf("ERROR: realloc failed.\n");
}
B = tmpB;
// B = realloc(B, nB1 + 1);
}
}
printf("\n");
printf("Array B: ");
nB = nB1;
for(i = 0 ; i < nB ; i++){
printf("%d ", B[i]);
}
printf("\n");
printf("Number of elements in array B: %d\n", nB);
printf("\n");
printf("Array C: ");
nC = nC1;
for(i = 0 ; i < nC ; i++){
printf("%d ", C[i]);
}
printf("\n");
printf("Number of elements in array C: %d\n", nC);
}
void main(){
int *A;
int *B;
int *C;
int nA, nB, nC, i, r, j;
nB = 0;
nC = 0;
printf("Enter the length of array A: ");
scanf("%d", &nA);
printf("\n");
A = malloc(nA * sizeof(int));
if (A == NULL){
printf("ERROR: malloc failed.\n");
return 1;
}
time_t t;
srand((unsigned)time(&t));
printf("Array A: ");
for(i = 0 ; i < nA ; i++){
r = rand() % 101;
A[i] = r;
printf("%d ", r);
}
printf("\n");
Array(A, nA, B, nB, C, nC);
}
到目前為止,我的代碼在以下情況下中斷:
來自nA
用戶輸入高於6。
當數組A
具有可以放在一個單獨的數組中的所有元素(例如B
或C
代碼運行良好。 但是,如果可以拆分元素,則數組A
最后一個元素位於B
或C
數組中時,不會在屏幕上正確顯示。
編輯:更新的代碼,以便更容易跟蹤我的錯誤。
#include <stdio.h>
#include <stdlib.h>
void Array(int *A, int nA, int *B, int nB, int *C, int nC){
int i;
int nB1 = 0;
int nC1 = 0;
int *tmpB;
int *tmpC;
B = malloc(1*sizeof(int));
if(B == NULL){
printf("ERROR: malloc B failed.\n");
return 1;
}
C = malloc(1*sizeof(int));
if(C == NULL){
printf("ERROR: malloc C failed.\n");
return 1;
}
printf("\n");
for(i = 0 ; i < nA ; i++){
if(A[i] <= 50){
// C[nC1] = A[i];
// nC1++;
// if( nC1 > 1){
// tmpC = realloc(C, sizeof(int) * nC1);
// if(tmpC == NULL){
// printf("ERROR: realloc C failed.\n");
// return 1;
// }
// C = tmpC;
// }
tmpC = realloc(C, sizeof(int) * nC1);
if(tmpC == NULL){
printf("ERROR: realloc C failed.\n");
return 1;
}
C = tmpC;
C[nC1++] = A[i];
// nC1++;
}
else{
// B[nB1] = A[i];
// nB1++;
// if(nB1 > 1){
// tmpB = realloc(B, sizeof(int) * nB1);
// if(tmpB == NULL){
// printf("ERROR: realloc B failed.\n");
// return 1;
// }
// B = tmpB;
// }
tmpB = realloc(B, sizeof(int) * nB1);
if(tmpB == NULL){
printf("ERROR: realloc B failed.\n");
return 1;
}
B = tmpB;
B[nB1++] = A[i];
// nB1++;
}
}
printf("\n");
printf("Array B: ");
nB = nB1;
for(i = 0 ; i < nB ; i++){
printf("%d ", B[i]);
}
printf("\n");
printf("Number of elements in array B: %d\n", nB);
printf("\n");
printf("Array C: ");
nC = nC1;
for(i = 0 ; i < nC ; i++){
printf("%d ", C[i]);
}
printf("\n");
printf("Number of elements in array C: %d\n", nC);
}
int main(){
int *A;
int *B;
int *C;
int nA, nB, nC, i, r;
printf("Enter the length of array A: ");
scanf("%d", &nA);
printf("\n");
A = malloc(nA * sizeof(int));
if (A == NULL){
printf("ERROR: malloc A failed.\n");
return 1;
}
time_t t;
srand((unsigned)time(&t));
printf("Array A: ");
for(i = 0 ; i < nA ; i++){
r = rand() % 101;
A[i] = r;
printf("%d ", r);
}
printf("\n");
Array(A, nA, B, nB, C, nC);
return 0;
}
邏輯誤差B[i] = A[i];
在您的情況下應為B[nB1] = A[i];
。 與C
數組相同,應該為C[nC1] = A[i]
(兩者都在循環中)。
另外,來自KillaBytes字節分析。 是的,您絕對應該在添加新值之前重新分配。 程序最終崩潰的原因可能是:
else { nB1++; // since you started at size 0 tmpB = realloc(B, sizeof(int) * nB1); //realloc to 0 = (sizeof(int) * 0) is bad if(tmpB == NULL){ printf("ERROR: realloc failed.\n"); } B = tmpB; B[nB1 - 1] = A[i];///*****KEY POINT, This happens at the very end*** }
盡管如此,還有許多其他問題,但核心邏輯沒有。 特別是對指針的理解。 我將嘗試列出您需要考慮的一些事項:
Array
函數(打印輸出除外)一無所有,原始的B
和C
保持不變。 A
, B
(在函數中), C
(在函數中)最后沒有釋放。 這個想法是,對於每個malloc / calloc(成功時realloc都會釋放),您將不得不在指針上調用free以避免任何內存泄漏:)只是一個瑣碎的事情,但是非常好的習慣。 if(tmpC == NULL){ printf("ERROR: realloc failed.\n"); }
應該
if(tmpC == NULL){ free(C);//unnecessary because the program is going to exit // I would argue to get used to this, to force the habit // to alway free all mallocs printf("ERROR: realloc failed.\n"); exit(-1);// -1 is a generic value, error code that is checked // if the caller cares to look (you can make it any int) }
B
和C
Array()
之外的值,則有幾種方法,我將演示一種方法。 void Array(int *A, int nA, int **B, int *nB, int **C, int *nC){ // funciton signature
每當在此函數中使用B
, nB
, C
, nC
時,請使用*B
, *nB
, *C
, *nC
。 例如:
*B = malloc((*nB1+1)*sizeof(int)); *C = malloc((*nC1+1)*sizeof(int));
從main
對該函數的調用應為:
printf("\n");
Array(A, nA, &B, &nB, &C, &nC);
我想我會設法解決這個問題。 我發現您的代碼存在一些值得注意的問題,可以通過對您的實現進行一些結構性更改來解決。 一些較小的:
void main() {
// Code above here left out.
A = malloc(nA * sizeof(int));
if (A == NULL){
printf("ERROR: malloc failed.\n");
return 1; // Might be a problem here.
}
如果沒有足夠的內存分配給A
,則在main中返回一個整數。 這可能會在某些編譯器上引起問題-或者,如果您通常不喜歡警告,從void main
到int main
的簡單修復將清除此問題。
第二,在函數Array
中
void Array(int *A, int *nA, int *B, int *nB, int *C, int *nC)
但是,您開始將nA nB
和nC
用作int
而不是int *
,這是類型不匹配的。 您可以更改為
void Array(int *A, int nA, int *B, int nB, int *C, int nC)
最后也是最重要的一點是,使用未初始化的ints
為傳入的數組創建內存會遇到堆錯誤:
int nB1;
int nC1;
B = malloc((nB1 + 1)*sizeof(int));
C = malloc((nC1 + 1)*sizeof(int));
最好不使用nB1
和nC1
而只向數組添加一個int
。
B = malloc(1*sizeof(int));
C = malloc(1*sizeof(int));
您應該先檢查傳入的B
和C
是否為空數組,然后根據需要添加內存。
if (A[i] <= 50){
C[i] = A[i];
nC1++;
// The idea here is to have a new array with basically
// no length so that each time one element passes to either
// B or A array that array gets increased at the same
// time as nC or nB
tmpC = realloc(C, sizeof(int) * nC1);
if (tmpC == NULL){
printf("ERROR: realloc failed.\n");
}
C = tmpC;
}
tmpC
被重新分配了,但是C
從未被分配更多的空間,因此在分配值C[i] = A[i]
會崩潰。 您需要擴展維護數組C
和B
編輯
忽略有關重新分配的注釋,您進行的realloc
操作就可以了。
遍歷數組A
中的每個元素,如果該值小於或等於50,則插入數組C
否則插入B
。 但是,您可能有一些元素滿足第一個條件,但隨后又可以滿足下一個條件。 然后,您像這樣分配B[i] = A[i]
但如上所述,您在A
元素3處,但在B
元素1處進行插入,因此使用i
來對兩者進行迭代都是不正確的。 遵循SGM1的建議,使用nB1
和nC1
讀取每個數組,也請ryyker提出有關重新分配的評論。
我每次都能編譯並運行此程序,但是現在您必須處理現在實際分配的值:
for (i = 0; i < nA; i++){
if (A[i] <= 50){
C[nC1] = A[i];
nC1++;
tmpC = (int *)realloc(C, sizeof(int) * nC1);
if (tmpC == NULL){
printf("ERROR: realloc failed.\n");
}
C = tmpC;
// C = realloc(C, nC1 + 1);
}
有一些錯誤。 編譯器標記了很多錯誤/警告(即,始終使用-Wall
編譯)
在Array
原型中, nA
被定義為*nA
[一個指針],但是您在整個正文中都使用了nA
。
*nB
和*nC
是正確的,但是您需要在底部附近:
*nB = nB1;
*nC = nC1;
所有陣列都有很多復制代碼。 每個數組都有一個自定義循環來打印它。 為了簡化,創建一個“打印數組”功能。
B
和C
的重新分配是相似的,因此,再次創建一個公共函數。
除了其他錯誤外,雖然Array
創建了B
和C
,但它無法將更新后的值傳遞回main
。 因此,在原型中,我們需要int **Bp
和int **Cp
。
Array
總共有兩個輸入值和四個返回值。
這是更正后的代碼[請原諒免費的樣式清理]:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// prtarray -- print an array
void
prtarray(int *arr,int count,const char *sym)
{
printf("\n");
printf("Array %s:",sym);
for (int i = 0; i < count; i++)
printf(" %d ", arr[i]);
printf("\n");
printf("Number of elements in array %s: %d\n",sym,count);
}
// growarray -- grow array
int *
growarray(int *arr,int *pcount,int val)
{
int off;
off = *pcount;
arr = realloc(arr,sizeof(int) * (off + 1));
arr[off] = val;
*pcount = off + 1;
return arr;
}
// BUGFIX: we need "int nA" and _not_ "int *nA"
#if 0
void
Array(int *A, int *nA, int *B, int *nB, int *C, int *nC)
#else
void
Array(int *A, int nA, int **Bp, int *nB, int **Cp, int *nC)
#endif
{
#if 1
int *B = NULL;
int *C = NULL;
#endif
int i;
printf("\n");
for (i = 0; i < nA; i++) {
if (A[i] <= 50)
C = growarray(C,nC,A[i]);
else
B = growarray(B,nB,A[i]);
}
*Bp = B;
*Cp = C;
}
int
main()
{
int *A;
int *B;
int *C;
int nA;
int nB;
int nC;
nB = 0;
nC = 0;
printf("Enter the length of array A: ");
scanf("%d", &nA);
printf("\n");
A = malloc(nA * sizeof(int));
if (A == NULL) {
printf("ERROR: malloc failed.\n");
return 1;
}
time_t t;
srand((unsigned) time(&t));
for (int i = 0; i < nA; i++)
A[i] = rand() % 101;
prtarray(A,nA,"A");
#if 0
Array(A, nA, B, nB, C, nC);
#else
Array(A, nA, &B, &nB, &C, &nC);
#endif
prtarray(B,nB,"B");
prtarray(C,nC,"C");
return 0;
}
但是,動態數組因使用struct
來控制事物而“呼喊”。 代碼變得更加簡單:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// array control
struct array {
int *arr_data; // data
int arr_count; // array count
const char *arr_sym; // array name
};
// arrinit -- initialize array
void
arrinit(struct array *arr,const char *sym)
{
arr->arr_data = NULL;
arr->arr_count = 0;
arr->arr_sym = sym;
}
// arrprint -- print an array
void
arrprint(struct array *arr)
{
printf("\n");
printf("Array %s:",arr->arr_sym);
for (int i = 0; i < arr->arr_count; i++)
printf(" %d ", arr->arr_data[i]);
printf("\n");
printf("Number of elements in array %s: %d\n",arr->arr_sym,arr->arr_count);
}
// arrgrow -- grow array
void
arrgrow(struct array *arr,int val)
{
int off;
off = arr->arr_count;
arr->arr_data = realloc(arr->arr_data,sizeof(int) * (off + 1));
arr->arr_data[off] = val;
arr->arr_count = off + 1;
}
// BUGFIX: we need "int nA" and _not_ "int *nA"
void
Array(struct array *A, struct array *B, struct array *C)
{
int i;
int val;
printf("\n");
for (i = 0; i < A->arr_count; i++) {
val = A->arr_data[i];
if (val <= 50)
arrgrow(C,val);
else
arrgrow(B,val);
}
}
int
main()
{
struct array A;
struct array B;
struct array C;
int nA;
arrinit(&A,"A");
arrinit(&B,"B");
arrinit(&C,"C");
printf("Enter the length of array A: ");
scanf("%d", &nA);
printf("\n");
time_t t;
srand((unsigned) time(&t));
for (int i = 0; i < nA; i++)
arrgrow(&A,rand() % 101);
arrprint(&A);
Array(&A, &B, &C);
arrprint(&B);
arrprint(&C);
return 0;
}
更新:
這是一個干凈的包裝,用於上面的realloc
。
// qrealloc -- reallocate with null check
void *
qrealloc(void *ptr,size_t len)
{
#if 1
// what is normally sufficient
ptr = realloc(ptr,len);
if (ptr == NULL) {
fprintf(stderr,"qrealloc: realloc failure -- len=%lu\n",len);
exit(1);
}
#else
// what valgrind needs
void *tmp = realloc(ptr,len);
if (tmp == NULL) {
free(ptr);
fprintf(stderr,"qrealloc: realloc failure -- ptr=%p len=%lu\n",ptr,len);
exit(1);
}
ptr = tmp;
#endif
return ptr;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.