簡體   English   中英

C中數組中的動態內存分配

[英]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具有可以放在一個單獨的數組中的所有元素(例如BC代碼運行良好。 但是,如果可以拆分元素,則數組A最后一個元素位於BC數組中時,不會在屏幕上正確顯示。

編輯:更新的代碼,以便更容易跟蹤我的錯誤。

#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函數(打印輸出除外)一無所有,原始的BC保持不變。
  • AB (在函數中), 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)
                }
  • 現在,如果您想“返回” BC Array()之外的值,則有幾種方法,我將演示一種方法。
void Array(int *A, int nA, int **B, int *nB, int **C, int *nC){ // funciton signature

每當在此函數中使用BnBCnC時,請使用*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 mainint main的簡單修復將清除此問題。

第二,在函數Array

void Array(int *A, int *nA, int *B, int *nB, int *C, int *nC)

但是,您開始將nA nBnC用作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));

最好不使用nB1nC1而只向數組添加一個int

B = malloc(1*sizeof(int));
C = malloc(1*sizeof(int));

您應該先檢查傳入的BC是否為空數組,然后根據需要添加內存。

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]會崩潰。 您需要擴展維護數組CB

編輯

忽略有關重新分配的注釋,您進行的realloc操作就可以了。

遍歷數組A中的每個元素,如果該值小於或等於50,則插入數組C否則插入B 但是,您可能有一些元素滿足第一個條件,但隨后又可以滿足下一個條件。 然后,您像這樣分配B[i] = A[i]但如上所述,您在A元素3處,但在B元素1處進行插入,因此使用i來對兩者進行迭代都是不正確的。 遵循SGM1的建議,使用nB1nC1讀取每個數組,也請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;

所有陣列都有很多復制代碼。 每個數組都有一個自定義循環來打印它。 為了簡化,創建一個“打印數組”功能。

BC的重新分配是相似的,因此,再次創建一個公共函數。

除了其他錯誤外,雖然Array創建了BC ,但它無法將更新后的值傳遞回main 因此,在原型中,我們需要int **Bpint **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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM