Как динамически вставить элемент в последнюю позицию в массиве в C? - PullRequest
2 голосов
/ 29 мая 2020

Я новичок ie в C и пытаюсь вставить число в последнюю позицию в C так, чтобы размер массива со временем менялся.

Первый массив выглядит следующим образом:

temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};

Теперь, как мы можем вставить те значения в temp, которые равны != 0, в новый массив с определенной длиной 5: tmp

Вот что я пробую:

void push(int arr[], int value, int current){
  arr[current] = value;
}

int main(void) { 

  int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
  int tmp[5];

  for(int i=0;;i++){
    if(temp[i]) push(tmp, temp[i],sizeof(tmp)/sizeof(tmp[0]));
    // I don't put i < 10 int the loop initialization. Since the tmp's length is just 5

  }
  // I put sizeof(tmp)/sizeof(tmp[0]) there because we want at every time the tmp is inserted a new value,
  // it's length will change (increase by 1). 
  // So next loop round, the new value will be added to the last position
  // But I failed to do so

} 

Текущий выход :

exited segmentation fault
// I'd be very grateful if someone can also explain for me why this error happens

Желаемый выход :

tmp[5] = {1, 2, 5, 6, 8}

Ответы [ 4 ]

1 голос
/ 29 мая 2020

C не имеет динамических массивов c. Массивы имеют фиксированный размер, определяемый их определением. Вы можете выделять объекты с malloc(), которые ведут себя как массивы, но вы должны отслеживать их выделенный размер отдельно. Добавление элемента требует перераспределения массива, поэтому его адрес в памяти может измениться.

В вашем коде tmp имеет фиксированный размер 5 элементов. Вы можете поддерживать индекс, определяющий, сколько элементов используется, и обновлять его в функции push:

#include <stdio.h>

int push(int arr[], int value, size_t size, size_t *current) {
    if (*current < size) {
        arr[(*current)++] = value;
        return 0;
    } else {
        /* array is full */
        return -1;
    }
}

int main(void) { 
    int temp[10] = { 1, 2, 0, 0, 5, 6, 0, 8, 0, 0 };
    int tmp[5];
    size_t pos = 0;

    for (size_t i = 0; i < sizeof(temp) / sizeof(temp[0]); i++) {
        if (temp[i])
            push(tmp, temp[i], sizeof(tmp) / sizeof(tmp[0]), &pos);
    }

    printf("tmp:");
    for (size_t i = 0; i < pos; i++) {
        printf(" %d", tmp[i]);
    }
    printf("\n");
    return 0;
}
1 голос
/ 29 мая 2020

Проблема в том, что вы осуществляете доступ за пределами temp, потому что вы не указываете, когда остановиться в l oop.

Для массива c Dynami, когда вы не знаете количество элементов заранее, вы можете использовать realloc:

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

void push(int **arr, size_t *size, int value)
{
    int *ptr = realloc(*arr, sizeof(*ptr) * (*size + 1));

    if (ptr == NULL)
    {
        free(*arr);
        perror("push");
        exit(EXIT_FAILURE);
    }
    ptr[*size] = value;
    *size += 1;
    *arr = ptr;
}

int main(void)
{ 
    int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
    int *arr = NULL;
    size_t size = 0;

    for (size_t i = 0; i < sizeof temp / sizeof temp[0]; i++)
    {
        if (temp[i])
        {
            push(&arr, &size, temp[i]);
        }
    }
    for (size_t i = 0; i < size; i++)
    {
        printf("%d\n", arr[i]);
    }
    free(arr);
} 

Обратите внимание, что даже если он иллюстрирует использование расширяемого массива, этот пример считается плохим кодом, более надежным design позаботится о размере и сможет самостоятельно управлять выделением и освобождением:

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

typedef struct
{
    int *data;
    size_t size;
}  dyn_array;

dyn_array *create_dyn_array(void)
{
    dyn_array *arr = calloc(1, sizeof *arr);

    if (arr == NULL)
    {
        perror("create_dyn_array");
        exit(EXIT_FAILURE);
    }
    return arr;
}

void destroy_dyn_array(dyn_array *arr)
{
    free(arr->data);
    free(arr);
}

void push_dyn_array(dyn_array *arr, int value)
{
    int *ptr = realloc(arr->data, sizeof(*ptr) * (arr->size + 1));

    if (ptr == NULL)
    {
        destroy_dyn_array(arr);
        perror("push_dyn_array");
        exit(EXIT_FAILURE);
    }
    ptr[arr->size++] = value;
    arr->data = ptr;
}

int main(void)
{ 
    int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
    dyn_array *arr = create_dyn_array();

    for (size_t i = 0; i < sizeof temp / sizeof temp[0]; i++)
    {
        if (temp[i])
        {
            push_dyn_array(arr, temp[i]);
        }
    }
    for (size_t i = 0; i < arr->size; i++)
    {
        printf("%d\n", arr->data[i]);
    }
    destroy_dyn_array(arr);
}

Это лучше, но все же не идеально, потому что мы ограничены фиксированным типом (int), с некоторой дополнительной памятью мы можем адаптировать наш код для поддержки любого типа (используя generi c type void *), в качестве оптимизации массив Dynami c увеличивается в 2 раза вместо вызова realloc для каждого итерация:

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

/* Begin - This API is supposed to be in a header */

typedef struct
{
    void **data;
    size_t room;
    size_t size;
}  dynarray;

dynarray *dynarray_create(void)
{
    dynarray *array = calloc(1, sizeof *array);

    if (array == NULL)
    {
        return NULL;
    }
    array->data = malloc(sizeof(void *));
    if (array->data == NULL)
    {
        free(array);
        return NULL;
    }
    array->room = 1;
    return array;
}

void *dynarray_push(dynarray *array, void *data)
{
    if (data == NULL)
    {
        return NULL;
    }
    if (array->size == array->room)
    {
        array->room *= 2;

        void *ptr = realloc(array->data, array->room * sizeof(void *));

        if (ptr == NULL)
        {
            return NULL;
        }
        array->data = ptr;
    }
    array->data[array->size++] = data;
    return data;
}

void *dynarray_get(dynarray *array, size_t index)
{
    return array->data[index];
}

size_t dynarray_size(dynarray *array)
{
    return array->size;
}

void dynarray_destroy(dynarray *array, void (*func)(void *data))
{
    if (func != NULL)
    {
        for (size_t i = 0; i < array->size; i++)
        {
            func(array->data[i]);
        }
    }
    free(array->data);
    free(array);
}

/* End API */

int main(void)
{ 
    int temp[10] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
    dynarray *array = dynarray_create();

    if (array == NULL)
    {
        perror("dynarray_create");
        exit(EXIT_FAILURE);
    }
    for (size_t i = 0; i < sizeof temp / sizeof temp[0]; i++)
    {
        if (temp[i])
        {
            if (dynarray_push(array, &temp[i]) == NULL)
            {
                perror("dynarray_push");
                exit(EXIT_FAILURE);
            }
        }
    }

    size_t size = dynarray_size(array);

    for (size_t i = 0; i < size; i++)
    {
        int *data = dynarray_get(array, i);

        printf("%d\n", *data);
    }
    dynarray_destroy(array, NULL);
}
1 голос
/ 29 мая 2020

Что такое

пытается вставить число в последнюю позицию в C

Хотя вы получили пояснительный ответ от Дэвида Раньери , Я хочу показать самый простой подход, имея в виду, что вы новичок ie. Посмотрите на этот код: -

Код:

#include <stdio.h>
#include <stdlib.h>
#define SIZE 10

void push(int arr[], int value, int current){
  arr[current] = value;
}

int main(void) {

  int temp[SIZE] = {1, 2, 0, 0, 5, 6, 0, 8, 0, 0};
  int *tmp = NULL, count = 0, i, j;

  // Loop for counting non-zero values in temp array.
  for (i = 0; i < SIZE; ++i)
    if (temp[i])
        count++;

  // Dynamically allocating space for tmp along with checking errors if any.
  if((tmp = (int *)malloc(count * sizeof(int))) == NULL)
     {
         printf("Memory Not Available.\n");
         exit(-1);
     }

  for(i = 0, j = 0; i < SIZE; i++){
    if(temp[i])
        push(tmp, temp[i], j++);
  }

  // Printing your desired output.
  for(i = 0; i < count; ++i)
    printf("%d\t", tmp[i]);

    free(tmp);
}

Здесь размер tmp изменится в соответствии с ненулевыми элементами temp. Теперь, если вы хотите сделать массив temp массивом dynamic c, используйте тот же подход, что и для tmp, просто попросите пользователя во время выполнения ввести размер temp, а затем его элементы / значения а также.

1 голос
/ 29 мая 2020

Ваше определение push требует, чтобы 3-й параметр был позицией для размещения элемента. Однако выражение sizeof(tmp)/sizeof(tmp[0]) предоставляет размер массива и, таким образом, будет индексировать за последним элементом массива (потому что индексы в C go из 0..n-1). Это само по себе может вызвать ошибку сегментации.

Вы также не указали условие завершения для вашего l oop. Это будет продолжаться вечно.

Ваше решение может быть просто:

for(int i=0, j=0; i<10; i++)
   if(temp[i]) push(tmp, temp[i], j++);
...