【问题标题】:Extending arrays in C using pointers使用指针扩展 C 中的数组
【发布时间】:2021-10-14 05:10:54
【问题描述】:

我正在学习 C 语言中的指针。为了了解详细信息,我正在研究一个数组程序。我想要实现的是,如果数组的大小为 0(最初),则使用大小为 2 的 malloc 创建一个动态数组,然后在初始位置添加元素。

此外,当添加更多元素时,如果总元素 == 数组的大小,我使用 malloc 创建一个新数组,其大小是先前大小的两倍。我创建了一个临时数组,从前一个数组中复制元素,然后在最后添加新元素。问题是当我尝试打印元素时,我得到的是最后一个元素的地址而不是元素的地址。

这是完整的代码。

#include<stdio.h>
#include<stdlib.h>

void display(int *arr, int *total_elements)
{
    if(*total_elements==0){
        printf("No elements present in array\n");
        return;
    }
    else
    {
        for(int i=0;i< *total_elements;i++){
            printf("%d\t",*(arr+i));
        }
    }
}

void push(int *arr, int *size, int ele, int *total_elements)
{
    if(*size==0)
    {
        *arr = (int*)malloc(2*sizeof(int));
        arr[*size] = ele;
        *total_elements = *total_elements + 1;
        *size = *size + 2;
        return;
    }
    else if(*size>*total_elements)
    {
        arr[*total_elements] = ele;
        *total_elements = *total_elements + 1;
        return;
    }
    else if(*size==*total_elements)
    {
        int *temp,i;
        temp = (int*)malloc((*(size)*2)*sizeof(int));
        for(i=0;i < *size;i++)
        {
            temp[i] = *(arr+i);
        }
        temp[i]=ele;
        arr = temp;
        *size = (*size)*2;
        *total_elements = *total_elements + 1;
        for(int i=0;i< *total_elements;i++){
            printf("%d\t",*(arr+i));
        }
    }
}

void pop()
{
}

void main()
{
    int select=0;
    int *arr, size=0, total_elements = 0;
    while(select!=4)
    {
        printf("\nSelect a number\n1. push\n2. pop\n3. display\n4. exit\n");
        scanf("%d",&select);
        switch (select)
        {
            case 1: 
                printf("Enter element to push: ");
                int ele;
                scanf("%d",&ele);
                push(arr,&size,ele,&total_elements);
                break;
            
            case 3: 
                display(arr, &total_elements);
                break;

            case 4: break;
            
            default:
                break;
        }

    }
}

输入 3 个元素后(11,22,33)。 push 函数的打印输出。

11      22      33

显示函数的打印输出。

11      22      -1943936495

我确定在使用指针时推送函数有错误。为什么会这样?

【问题讨论】:

  • 如果允许,使用最近调用的GCC 作为gcc -Wall -Wextra -g(所有警告和调试信息)编译您的代码,并使用GDB 调试器和valgrind
  • 请注意,您的局部变量 arr 未初始化。我建议初始化每个指针(例如到NULL)。您可能想要定义一个返回指针的grow 函数并调用arr= grow(arr);
  • @BasileStarynkevitch 是的,我会添加增长功能以便更好地理解
  • 使用realloc代替自制增长代码。
  • *arr = (int*)malloc(2*sizeof(int)); 是一个错误。如果您没有看到错误消息,请重新配置您的编译器设置。尝试运行存在编译时错误的程序完全是浪费时间。

标签: arrays c pointers malloc


【解决方案1】:

由于arr = temp;push 函数可以正常工作。观察arr 实际上是push 函数内部的一个局部变量。当push 函数返回时,main 确实知道arr 变量曾经在push 中更改过。

当您将arr 传递给display 时,将发送 main 拥有的副本。如果您需要在另一个函数中更新arr(在这种情况下为push),则需要传递arr 的地址 - push(&amp;arr,&amp;size,ele,&amp;total_elements); 同样,push 函数现在应该接受int **arr 而不是@ 987654337@。另外,请确保在 push 中取消引用 arr 的次数正确。

push 中,您可以通过执行*arr = temp; 来更新arr。在此之后,arr 将指向 push 中的 malloced 的新数组,您可以将 arr 传递给您的 display 函数。

【讨论】:

  • 所以,你已经指出了错误是什么;还包括一个解决方案怎么样?
  • @babon 当我只添加 2 个元素并使用显示功能打印时,我得到了想要的结果。
  • @babon,您对main does not have any idea that the arr was changed 的看法是正确的。这只发生在我尝试扩展数组时,主要不知道更新。
【解决方案2】:

在您的代码中:

  1. arr 是数组指针。
  2. size 是当前填充/使用的元素数。
  3. total_elements已分配元素的数量。

您正在过度分配arr(使用total_elements),这很好。

但是,您将sizetotal_elements 的使用混为一谈。在display,你应该使用size

请注意,在main 中,您没有初始化arr [到NULL]。对于您的代码,这没关系,因为push 的实现方式。但是,通常最好将其设置为 NULL--见下文。

push 中,您没有调用者更新arr

另外,push 比它需要的更复杂(即)太多特殊情况。

如果main 初始化arr,那么push 可以只使用realloc(因为realloc 处理空指针就像处理malloc [内部])。

我们可以为包含您单独的标量值的数组创建一个控件struct,而不是将 3 个东西传递给 push。这大大简化了代码。我们只是将 [single] struct 指针传递给所有函数。


这是一些重构的代码。出于测试目的,我添加了一个case 5

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int *arr;                           // pointer to array data
    int size;                           // number of filled/inuse elements
    int total_elements;                 // number of allocated elements
} dynarr_t;

void
display(dynarr_t *dyn)
{

    if (dyn->size == 0) {
        printf("No elements present in array\n");
        return;
    }

    int totlen = 0;

    for (int i = 0;  i < dyn->size;  i++) {
        if (totlen >= 68) {
            printf("\n");
            totlen = 0;
        }
        int curlen = printf(" %d",dyn->arr[i]);
        totlen += curlen;
    }

    if (totlen > 0)
        printf("\n");
}

void
push(dynarr_t *dyn,int ele)
{

    // grow the array
    if (dyn->size >= dyn->total_elements) {
        // the amount here is arbitrary
        dyn->total_elements += 10;

        dyn->arr = realloc(dyn->arr,sizeof(*dyn->arr) * dyn->total_elements);

        // out of memory
        if (dyn->arr == NULL) {
            perror("push");
            exit(1);
        }
    }

    // append new element
    dyn->arr[dyn->size++] = ele;
}

// RETURNS: 1=valid, 0=empty
int
pop(dynarr_t *dyn,int *ele)
{

    // no elements in array
    if (dyn->size <= 0)
        return 0;

    // pop the last element
    *ele = dyn->arr[--dyn->size];

    return 1;
}

int
main(void)
{
    int select = 0;
    int ele;

    // allocate a pointer to the array control struct
    dynarr_t *dyn = calloc(1,sizeof(*dyn));

    while (select != 4) {
        printf("\nSelect a number\n1. push\n2. pop\n3. display\n4. exit\n");
        scanf("%d", &select);
        switch (select) {
        case 1:
            printf("Enter element to push: ");

            scanf("%d", &ele);
            push(dyn, ele);
            break;

        case 2:
            if (pop(dyn,&ele))
                printf("main: pop %d\n",ele);
            else
                printf("main: pop empty\n");
            break;

        case 3:
            display(dyn);
            break;

        case 4:
            break;

        case 5:  // internal test
            for (int ele = 1;  ele <= 100;  ++ele)
                push(dyn,ele);
            display(dyn);
            break;

        default:
            break;
        }
    }

    // free up the memory
    free(dyn->arr);
    free(dyn);

    return 0;
}

这是[5 4]的测试输出:


Select a number
1. push
2. pop
3. display
4. exit
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
 96 97 98 99 100

Select a number
1. push
2. pop
3. display
4. exit

【讨论】:

  • 这是一个干净的解决方案。我想用结构来做,但后来我改变了主意。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-08
  • 2018-06-23
  • 1970-01-01
  • 2014-02-26
  • 2018-01-04
相关资源
最近更新 更多