web-dev-qa-db-fra.com

Modification du tableau à l'intérieur de la fonction en C

J'apprends le C et je ne comprends pas pourquoi un tableau créé dans le principal ne changera pas à l'intérieur de la fonction, je suppose que le tableau passé est un pointeur, et le changement du pointeur aurait dû changer le tableau, non? quelqu'un peut-il expliquer ce qui se passe dans ce cas?

merci pour l'aide.

int main(){
    int i, length = 10;
    int array[length];

    for (i = 0 ; i < length ; i++)
        array[i] = i * 10;
    printf("Before:");
    print(array, length);
    change(array, length);
    printf("After:");
    print(array, length);

    return 0;
}

// Print on console the array of int
void print(int *array,int length)
{
    int i;
    for(i = 0 ; i < length ; i++)
        printf("%d ", array[i]);
    printf("\n");
}

// Change the pointer of the array
void change(int *array,int length)
{
    int *new = (int *) malloc(length * sizeof(int));
    int i;
    for(i = 0 ; i < length ; i++)
        new[i] = 1;
    array = new;
}

Je m'attendais à voir la sortie suivante:

Before:0 10 20 30 40 50 60 70 80 90 
After:1 1 1 1 1 1 1 1 1 1 

Ce que j'obtiens:

Before:0 10 20 30 40 50 60 70 80 90 
After:0 10 20 30 40 50 60 70 80 90 
8
Victor Ferreira

Dans c vous ne pouvez pas passer une variable par référence, la variable array que vous affectez à l'intérieur de la fonction contient initialement la même adresse que le pointeur passé, mais c'est une copie de celle-ci donc sa modification ne modifiera pas le pointeur passé.

Vous devez passer l'adresse du pointeur pour pouvoir le modifier, comme ceci

// Change the pointer of the array
void change(int **array, int length)
{
    *array = malloc(length * sizeof(int));
    if (*array == NULL)
        return;
    for (int i = 0 ; i < length ; i++)
        (*array)[i] = 1;
}

Ensuite, dans main(), vous ne pouvez pas attribuer à un tableau, le faire à travers ce type de fonction est certainement un comportement indéfini. Le tableau défini dans main() est alloué sur la pile et vous ne pouvez rien attribuer à un tableau car ils sont non - inscriptibles lvalues ​​ afin que vous ne puissiez pas le faire pointer vers un emplacement de mémoire de tas obtenu avec malloc(), vous devez passer un pointeur comme celui-ci

int *array;
change(&array, length);
free(array);

Si vous voulez que la fonction remplace le tableau précédent, elle devra free() les malloc() ed données ( noter qu'en passant NULL à free() est bien défini ), donc

// Change the pointer of the array
void change(int **array, int length)
{
    free(*array);

    *array = malloc(length * sizeof(int));
    if (*array == NULL)
        return;
    for (int i = 0 ; i < length ; i++)
        (*array)[i] = 1;
}

puis dans main()

int *array;
array = NULL;
change(&array, length);
change(&array, length);
change(&array, length);
change(&array, length);
free(array);

fera ce que vous voulez apparemment.

14
Iharob Al Asimi
            #include<stdio.h>
            #include<stdlib.h>

            // Print on console the array of int
            void print(int *array,int length)
            {
                int i;
                for(i = 0 ; i < length ; i++)
                    printf("%d ", array[i]);
                printf("\n");
            }

            // Change the pointer of the array
            void change(int **array,int length)
            {
                int i;
                int *ar;
                ar = (int *)malloc(sizeof(int *) * length);
                for(i = 0 ; i < length ; i++)
                    ar[i] = 1;
                (*array) = ar;
            }

            int main(){
                int i, length = 10;
                int *array;
                array = (int *)malloc(sizeof(int *) * length);

                for (i = 0 ; i < length ; i++)
                    array[i] = i * 10;
                printf("Before:");
                print(array, length);
                change(&array, length);
                printf("After:");
                print(array, length);

                return 0;
            }
0
yogesh

Vous passez un pointeur vers le tableau array vers la fonction change. Dans cette fonction, vous créez un autre tableau appelé new (en utilisant new comme nom est une mauvaise idée) puis l'affectez au paramètre de fonction créé localement array. Vous ne pas modifier le pointeur dans votre fonction main. Si vous le souhaitez, vous devez utiliser

array = change(array,length);

dans votre fonction principale et

int *change(int *array, int length) {
    int *variable_called_new =(int *)malloc(length*sizeof(int));
    [...]
    return variable_called_new
}

dans votre fonction change.

0
nsilent22

donc lorsque vous passez le tableau, vous obtenez l'adresse de son début:

mémoireadresse

| -junk- | 1000

| --- 0 --- | 1008 <- début de votre tableau

| --- 10-- | 1012

. . . .

lorsque vous obtenez le pointeur dans votre fonction, sa valeur est 1008 (exemple), donc changer cela signifie seulement que vous pointez maintenant vers un autre endroit. ce n'est pas ce que tu veux. vous pouvez changer les entiers pointés directement via l'opérateur *, donc *array = 99; changera le premier élément, *(array+1) = 98; le second et ainsi de suite. vous pouvez également, plus naturellement, utiliser l'opérateur []. donc dans votre fonction array[0] = 99; changera réellement le tableau d'origine.

0
rustypaper

Pour utiliser le passage par valeur:
Apportez la modification suivante:
Dans la fonction change(...), remplacez:

int i;for(i=0;i<length;i++)new[i] = 1;

À:

int i;for(i=0;i<length;i++)array[i] = 1;
                           ^^^^^

MODIFIER :
Mais pour utiliser pass by reference:

//To change the contents of a variable via a function call
//the address of that variable has to be passed. So, if you
//want to change the contents of an array of int, i.e. int *array, you 
//need to pass its address, not the variable itself,  using the 
//address of operator, it would look like this &array (read _the address of
// pointer to int "array")
//This requires you to change the prototype of your function:
void change2(int **a, int len)
{
    int i;
    for(i=0;i<len;i++) (*a)[i] = 1;//parenthesis bind * to a to assure 
                                   //array of pointers to int ( *[] )is populated
                                   //
}

Ensuite, en général, apportez les modifications suivantes, et cela fonctionnera comme vous le vouliez:

int main(){
    int i,length=10;
    int *array;

    array = calloc(length, sizeof(int));
    if(!array) return 0;
    //or malloc if preferred.  But note, in C, 
    //casting the output is not required on either.
    //array = malloc(length*sizeof(int));
    //if(!array) return 0;

    for(i=0;i<length;i++)array[i]=i*10;

    printf("Before:");print(array,length);
    change2(&array,length);
    printf("After:");print(array,length);

    free(array);

    return 0;
}
0
ryyker

Votre tableau principal est un tablea. Il se désintègre en un pointeur, pour produire le comportement que vous attendez, mais c'est pas un pointeur.

int a[10];
int* p = a; // equivalent to &a[0]; create a pointer to the first element
a = p;      // illegal, a is NOT a pointer.

Ce que fait votre code, c'est copier l'adresse d'un dans une variable locale de fonction. Le modifier n'aura pas plus de différence à l'extérieur que de changer de longueur.

void change(int* local_ptr, size_t length)
{
    local_ptr = 0;
    length = 0;
}

int main()
{
    int a[10];
    int length = 10;
    printf("before a=%p, length=%d\n", a, length);
    change(a, length);  // we copied 'a' into 'local_ptr'. 
    printf("after a=%p, length=%d\n", a, length);
}

Si vous souhaitez modifier un pointeur de l'appelant, vous devrez utiliser la syntaxe pointeur à pointeur:

void change(int** ptr, size_t length)
{
    // change the first element:
    **ptr = 0;
    // change the pointer:
    *ptr = 0;
    // but ptr itself is a function-local variable
    ptr = 0;  // local effect
}

Cependant: il y a un problème avec ce que vous essayez de faire qui va plus loin que cela.

Dans votre code, "int a" est un tableau sur la pile, pas un pointeur alloué; vous ne pouvez pas le libérer et vous devez éviter de mélanger les pointeurs tas/pile de cette façon, car vous finirez par libérer la mauvaise chose.

0
kfsone