Void功能:从数组中删除元素?

时间:2016-12-05 21:53:59

标签: c arrays

我想创建一个从数组中删除元素的函数。

我尝试自己制作这个功能,然而,并没有完全成功:

void remove_element(int* array, int number, int array_length)
{
    int i, j;

    for (i = 0; i < array_length; i++){
        if (array[i] == number) {
            for (j = i; j < array_length; j++)
                array[j] = array[j+1];
            array_length--;
        }
    }
}

我注意到的第一件事是在main中调用函数后,array_lenght没有改变,因此删除元素后数组的长度保持不变。

所以第一个问题是如何在void函数内改变数组的长度?

无法正常工作的第二件事是,如果数组中的两个或多个相同的数字彼此相邻,例如,如果数组包含1,1,3,4,5,6并且用户想要删除1函数将只删除一个元素。

我的输出示例(错误):

1,1,3,4,5,6 after fucntion 1,3,4,5,6

由于

5 个答案:

答案 0 :(得分:4)

在当前签名中,您无法修改数组,因为返回新数组还需要返回新长度。

有很多方法可以做到这一点,这是一种单循环方式:

void
remove_element(int* array, int number, int *array_length)
{
    int i, j;

    for (i = 0, j=0; i < *array_length; i++) {
        if (array[i] != number)
            array[j++] = array[i];
    }
    *array_length = j;
}

这样做会改变初始数组和保持调用者长度的变量,你必须通过引用传递array_length的值,比如

int* some_array, some_array_length, n;

remove_element(some_array, n, &some_array_length)

其他方法是返回新的长度并改变数组或在堆中分配一个新数组并返回分配的数组和新的长度。

答案 1 :(得分:2)

除了你的问题的另一个答案,如果你平均可以做一次以上的删除(实际上每次通话超过一次),最好不要随后转移所有值一次又一次。试试这个:

void remove_element(int *array, int number, int *array_length) {
    for(int iRead = 0, iWrite = 0; iRead < *array_length; iRead++) {
        if(array[iRead] == number)
            continue; /* skip without increasing iWrite */
        if(iWrite < iRead) /* it works without this line, too, what's better depends */
            array[iWrite] = array[iRead];
        iWrite++;
    }
    *array_length = iWrite;
}

这是如何运作的,例如array = {1,1,2,2,3}number = 2

1 1 2 2 3
^ iRead
^ iWrite
(increases both, writes nothing)

1 1 2 2 3
  ^ iRead
  ^ iWrite
(increases both, writes nothing)

1 1 2 2 3
    ^ iRead
    ^ iWrite
(continue happens: increases only iRead)

1 1 2 2 3
      ^ iRead
    ^ iWrite
(continue happens: increases only iRead)

1 1 2 2 3
        ^ iRead
    ^ iWrite
(writes 3 to iWrite, increases both)

1 1 3 2 3
          ^ iRead = 5
      ^ iWrite = 3
(iRead is no longer < *array_length, loop stops, 3 == iWrite is the new length)

答案 2 :(得分:1)

因为array_length没有作为指针传递,所以你在堆栈上有它的副本,所以在你离开这个函数之后,你仍然有旧值。在找到相同的数字后,您可以在此处使用memmove或memcpy而不是遍历整个数组。您没有删除数组中的下一个1的原因是,因为当您在i = 0时 - >&gt; array [0] == 1,但是当你移回所有数字然后你将第二个1移动到数组[0],之后没有检查它,因为在你完成迭代之后你只需增加i,而不检查你移动到当前是什么array [i]的值与前一个相同。

void remove_element(int *array, int number, int *array_length){
    int sameValues = 0;
    for(int i = 0; i < *array_length; i++){
        while(array[i] == number){
            *array_length--;
            sameValues++;
        }
        if(sameValues > 0){
            if(i < *array_length){
                memmove(&array[i], &array[i + sameValues], (*array_length - i) * sizeof(int));
            }
            sameValues = 0;
        }
    }
}

为了使它更加动态,你可以使用realloc(并在删除成员后实际调整数组所占用的空间,但是你要么需要返回新的指针,要么你需要指向你的堆栈上的指针调用函数:

void remove_element(int **array, int number, int *array_length){
    int sameValues = 0;
    for(int i = 0; i < *array_length; i++){
        while((*array)[i] == number){
            *array_length--;
            sameValues++;
        }
        if(sameValues > 0){
            if(i < *array_length){
                memmove(&(*array)[i], &(*array)[i + sameValues], (*array_length - i) * sizeof(int));
            }
            realloc(*array, *array_length);
            sameValues = 0;
        }
    }
}

P.S。要使用memmove,您需要包含string.h

答案 3 :(得分:1)

声明数组时,编译器会影响一定量的内存,而使用数组结构则无法更改它。有2个解决方案,更改您的array length,但您仍然可以访问最后一个“框”或重新定义所需大小的数组。 第一种情况:

void remove_element(int* array, int number, int * array_length){

int i = 0,j = 0;

while( i < *(array_length)-1){
    if(array[i] == number && !find){
        i++; //we step over
        find = 1; //we find 1 element stop remove
    }
    array[j] = array[i];
    i++;
    j++;   
}
*(array_length)--;
}

int * array_length是指向内存的指针,因此当您返回主页时,您的更改会保留。在你的例子中,在remove_element array_length等于6之前,在它之后是5.但是你仍然可以做数组[5](第6个元素在c中引起符号0到5)。

第二案

int * remove_element(int * array, int number, int * array_length){

int * new_array = malloc((array_length -1) * sizeof(int)); // len - 1 cause we want to delet only 1 element

int i = 0;
int j = i;
int find = 0;
while( i < *(array_length)-1){
    if(array[i] == number && !find){
        i++; //we step over
        find = 1; //we find 1 element stop remove
    }
    new_array[j] = array[i];
    i++;
    j++;   
}
if (array[array_length] != number && !find){ //if we didn't find att all the element return array
    return array;
} else {
    *(array_length)--;
    return new_array;
}
}

您必须返回new_array,因为您的main中的int array[6]是常量:您无法使用array = new_array更改它。

编辑:是的当然,当你不再需要你的阵列时,你必须用free(array)释放它(或者它在进程结束时自动完成,但它不是正确的代码)

还有一个更短的方法来添加指针,但是你的c lvl似乎太复杂了:)

答案 4 :(得分:1)

根据您的评论,我会这样做:

#include <stdio.h>

void remove_element(int number, int *arr, size_t *size);

int main(void){
    int arr[] = {1,1,3,4,5,6};

    long unsigned int arrSize;
    int number = 1;
    arrSize = sizeof arr / sizeof arr[0];

    printf("Before:\n");
    for ( size_t i = 0 ; i < arrSize ; i++ ){
        printf("%d ", arr[i]);
    }

    printf("\nAfter:\n");
    remove_element( number, arr, &arrSize );

    for ( size_t j = 0 ; j < arrSize ; j++ ){
        printf("%d ", arr[j]);
    }
    printf("\n");
}

void remove_element(int number, int *arr, size_t *size){
    int arrTemp[*size];
    long unsigned int j = 0,c;

    for ( size_t i = 0 ; i < *size ; i++ ){
        if ( arr[i] == number ){
                continue;
        }else{
            arrTemp[j] = arr[i];
            j++;
        }
    }

    for ( size_t k = 0 ; k < j ; k++ ){
        arr[k] = arrTemp[k];
    }

    c = j;
    while ( *size > c ){
        arr[c] = 0;
        c++;
    }

    *size = j;
}

输出:

Before:
1 1 3 4 5 6 
After:
3 4 5 6

顺便问一下你说的话:

Examples of output:

1,1,3,4,5,6 after fucntion 1,3,4,5,6

在你的评论中你说:

It doesn't matter how many same numbers there are, in that case above if user wants to remove 1, all 1 's should be removed. 

请下定决心。