C中数组中的动态内存分配

时间:2016-03-28 19:58:29

标签: c arrays malloc realloc

我花了几个小时试图调试我的代码,但我没有这样做。我认为问题在于我没有完全理解动态内存分配,但我也可能犯了其他一些错误。这里的问题更多的是一个个人问题,如果有人发现这个问题没有实现,我很抱歉,#34;让它与他人相关"。

我已获得下一个分配:

从区间0-100中的A[]个随机元素中创建一个数组n。创建一个拆分两个数组的函数,例如:array 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;
}

3 个答案:

答案 0 :(得分: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,{{1 },*C。例如:

    *B = malloc((*nB1+1)*sizeof(int));
    *C = malloc((*nC1+1)*sizeof(int));

来自*nC的函数调用应为:

main

答案 1 :(得分:0)

我猜我会试着抓住这个。我发现您的代码存在一些值得注意的问题,可以通过对您的实现进行一些结构性更改来解决。一些较小的:

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));

最好只在不使用intnB1的情况下向数组中添加一个nC1

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是realloc&#39;但C永远不会获得更多空间,因此在分配值C[i] = A[i]时会崩溃。您需要扩展维护数组CB

修改

忽略有关重新分配的评论,您的realloc操作没问题。

遍历数组A中的每个元素,如果值小于或等于50,则插入数组C,否则B。但是,您可能有一些元素满足第一个条件,但可以满足下一个条件。然后按照B[i] = A[i]进行分配,但如上所述,您位于A中的元素3,但是您在B中的元素1处插入,因此使用i迭代两者都不是正确。按照 SGM1 的建议,使用nB1nC1以及 ryyker 读取每个数组,以获取有关重新分配的评论。< / p>

我每次都能编译并运行它,但是现在你必须处理实际分配值:

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);
    }

答案 2 :(得分:-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;
}