2 votes

Question de débutant. Comment faire passer des pointeurs dans une fonction en C ?

Je viens de commencer à apprendre le C (je viens d'un environnement C#). Pour mon premier programme, j'ai décidé de créer un programme pour calculer des facteurs. Je dois passer un pointeur dans une fonction et ensuite mettre à jour la variable correspondante.

Je reçois l'erreur 'Conflicting types for findFactors', je pense que c'est parce que je n'ai pas montré que je souhaite passer un pointeur comme argument lorsque je déclare la fonction findFactors. Toute aide serait grandement appréciée !

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

int *findFactors(int, int);

int main (int argc, const char * argv[]) 
{
    int numToFind;

do {
    printf("Enter a number to find the factors of: ");
    scanf("%d", &numToFind);    
} while (numToFind > 100);

    int factorCount;
findFactors(numToFind, &factorCount);

return 0;
}

int *findFactors(int input, int *numberOfFactors)
{
int *results = malloc(input);
int count = 0;
for (int counter = 2; counter < input; counter++) {
    if (input % counter == 0){
        results[count] = counter;
        count++;
        printf("%d is factor number %d\n", counter, count);
    }
}

return results;
}

3voto

unwind Points 181987

Modifiez la déclaration pour qu'elle corresponde à la définition :

int *findFactors(int, int *);

2voto

Je m'excuse d'ajouter une autre réponse, mais je pense que personne n'a couvert tous les points qui doivent être couverts dans votre question.

1) Chaque fois que vous utilisez malloc() pour allouer dynamiquement de la mémoire, vous devez également free() quand vous aurez terminé. Le système d'exploitation va, en général, faire le ménage après vous, mais considérez que vous avez un processus pendant votre exécutable qui utilise de la mémoire. Lorsque ce processus est terminé, si vous free() que la mémoire de votre processus a plus de mémoire disponible. C'est une question d'efficacité.

Pour utiliser correctement la gratuité :

int* somememory = malloc(sizeyouwant * sizeof(int));
// do something
free(somememory);

Facile.

2) Chaque fois que vous utilisez malloc Comme d'autres l'ont fait remarquer, l'allocation réelle est en octets, vous devez donc effectuer les opérations suivantes malloc(numofelements*sizeof(type)); . Il existe une autre fonction, moins largement utilisée, appelée calloc qui ressemble à ceci calloc(num, sizeof(type)); ce qui est peut-être plus facile à comprendre. calloc initialise également votre mémoire à zéro .

3) Il n'est pas nécessaire d'exprimer le type de retour de la fonction malloc . Je sais que de nombreux livres de programmation suggèrent de le faire et que le C++ impose de le faire (mais en C++, vous devriez utiliser la fonction new / delete ). Voir cette question .

4) Votre signature de fonction était en effet incorrecte - les signatures de fonction doivent correspondre à leurs fonctions.

5) Pour ce qui est de renvoyer des pointeurs à partir de fonctions, c'est quelque chose que je décourage mais ce n'est pas mauvais en soi. Deux points à mentionner : gardez toujours le point 1) à l'esprit. I a demandé exactement quel était le problème et il s'agit essentiellement de garder une trace de ces free() appels. En tant qu'utilisateur plus avancé, il faut également se préoccuper du type d'allocateur.

Un autre point ici, considérez cette fonction :

int* badfunction()
{
    int x = 42;
    int *y = &x;
    return y;
}

C'est mauvais, mauvais, mauvais. Ce qui se passe ici est que nous créons et retournons un pointeur vers x qui n'existe que tant que vous êtes dans badfunction . Quand vous revenez, vous avez l'adresse d'une variable qui n'existe plus parce que x est généralement créé sur la pile. Vous en apprendrez davantage à ce sujet au fil du temps ; pour l'instant, pensez simplement que la variable n'existe pas au-delà de sa fonction.

Notez que int* y = malloc(... est un cas différent - cette mémoire est créée sur le tas à cause du malloc et survit donc à la fin de ladite fonction.

Que recommanderais-je comme signature de fonction ? En fait, j'opterais pour shybovycha avec une légère modification :

int findFactors(int* factors, const int N);

Mes changements ne sont que des préférences personnelles. J'utilise const pour que je sache que quelque chose fait partie de l'entrée d'une fonction. Ce n'est pas strictement nécessaire avec un simple int, mais si vous passez des pointeurs, rappelez-vous que la mémoire source peut être modifiée à moins que vous n'utilisiez la fonction const avant lui, sur lequel votre compilateur devrait vous avertir si vous essayez de le modifier. C'est donc juste une habitude dans ce cas.

Le deuxième changement est que je préfère les paramètres de sortie sur la gauche parce que je pense toujours de cette façon, c'est-à-dire output = func(input) .

Pourquoi peut-on modifier les arguments d'une fonction lorsqu'un pointeur est utilisé ? Parce que vous avez transmis un pointeur à une variable. Il s'agit simplement d'une adresse mémoire - lorsque nous la "déréférençons" (accédons à la valeur à cette adresse), nous pouvons la modifier. D'un point de vue technique, le C est strictement un système de transmission par valeur. Les pointeurs sont eux-mêmes des variables contenant des adresses mémoire et le contenu de ces variables est copié dans votre fonction. Ainsi, une variable normale (disons int ) est juste une copie de ce que vous avez passé en entrée. int* factors est une copie de l'adresse de la variable pointeur que vous lui transmettez. Par conception, l'original et cette copie pointent tous deux vers la même mémoire, de sorte que lorsque nous les déréférençons, nous pouvons modifier cette mémoire à la fois dans la fonction appelante et dans la fonction originale.

J'espère que cela clarifie certaines choses.

1voto

Benoit Thiery Points 3720

EDIT : pas de référence en C (caractéristique du C++)

N'oubliez pas de modifier numberOfFactors dans la méthode (ou de supprimer ce paramètre s'il n'est pas utile). La signature au début de votre fichier doit également correspondre à la signature de l'implémentation à la fin (c'est l'erreur que vous recevez).

Enfin, votre malloc pour les résultats n'est pas correct. Tu dois faire ça :

int *results = malloc(input * sizeof(int));

0voto

RobLucas Points 180
int* ip   <- pointer to a an int
int** ipp <- pointer to a pointer to an int.

0voto

shybovycha Points 3199

int *findFactors(int, int); indique que vous voulez renvoyer un pointeur depuis cette fonction (il est préférable d'utiliser des astérisques plus proches du nom du type : int* moo(); - cela évite les malentendus, je pense).

Si vous voulez changer dynamiquement l'argument de la fonction (ce qui est un meilleur moyen que le simple pointeur de retour), vous devriez juste utiliser l'argument comme si vous aviez déjà cette variable.

Et la dernière, votre erreur : malloc(X) alloue X octets donc si vous voulez allouer de la mémoire pour un tableau, vous devez utiliser malloc(N * sizeof(T)); , donde N est la taille de votre tableau et T est son type. Ex : si vous voulez avoir int *a vous devriez le faire : int *a = (int*) malloc(10 * sizeof(int)); .

Et maintenant voici votre code, corrigé (quant à moi) :

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

int findFactors(int, int*);

int main(int argc, char **argv) 
{
  int numToFind, *factors = 0, cnt = 0;

  do 
  {
    printf("Enter a number to find the factors of: ");
    scanf("%d", &numToFind);    
  } while (numToFind > 100);

  cnt = findFactors(numToFind, factors);

  printf("%d has %d factors.\n", numToFind, cnt);

  return 0;
}

int findFactors(int N, int* factors)
{
  if (!factors)
    factors = (int*) malloc(N * sizeof(int));

  int count = 0;

  for (int i = 2; i < N; i++) 
  {
    if (N % i == 0)
    {
      factors[count++] = i;
      printf("%d is factor number #%d\n", i, count);
    }
  }

  return count;
}

Nota: n'oubliez pas d'initialiser vos pointeurs à tout moment (comme je l'ai fait). Si vous voulez appeler une fonction, en passant un pointeur comme argument, vous devez être sûr qu'il a la valeur de 0 au moins avant l'appel de la fonction. Sinon, vous obtiendrez une erreur d'exécution.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X