1
votes

Liste liée - Fonction d'insertion de base

J'ai écrit un programme qui obtient une certaine valeur et le met dans une liste chaînée triée. Le problème est qu'après avoir entré la première valeur le programme s'arrête et il n'exécute même pas la fonction d'insertion

Je sais que le problème est de passer l'argument à la fonction d'insertion Mais je ne sais pas comment y remédier.

    #include <stdio.h>
#include <stdlib.h>
struct record{
    int data;
    struct record *nextptr;
};
void insert (struct record *ptr,int value);
void printList(struct record *ptr);

int main() {
    struct record *headptr = NULL;
    for (int i = 0; i < 4; ++i) {
        int data;
        printf("Enter your value");
        scanf("%d", &data);
        insert(headptr, data);
    }
    printList(headptr);


    return 0;
}
void insert (struct record *ptr,int value){
    printf("WE ARE IN THE INSERT FUNCTION");
    struct record *newptr = (struct record *) malloc(sizeof(struct record));
    newptr->data=value;
    newptr->nextptr=NULL;
    struct record *curptr;
    curptr=ptr;

    while(value >= (curptr->data)){
        curptr=curptr->nextptr;
    }
    if (curptr==NULL){
        ptr=newptr;
    }
    else{
        newptr->nextptr=curptr;
    }

}
void printList(struct record *ptr){
    while((*ptr).nextptr != NULL){
        printf("%d", ptr->data);
        ptr=ptr->nextptr;
    }
}

Résultat:

/ Users / Danial / CLionProjects / Example / cmake-build-debug / Exemple Entrez votre valeur3

Processus terminé avec le code de sortie 11


2 commentaires

Le problème est que vous passez un pointeur vers votre fonction d'insertion, toute modification apportée au pointeur à l'intérieur de la fonction ne la fera pas sortir de la fonction, pour ce faire, vous devez passer un pointeur vers le pointeur *, puis à l'intérieur de la fonction use ().


ce que vous faites est l'équivalent de ceci: int foo (int n) {n = 1; }


4 Réponses :


0
votes

Ici, vous déclarez headptr et le définissez sur NULL:

while (value >= (curptr->data)) {

Ensuite, vous le passez à insert code >:

void insert(struct record *ptr, int value)

Donc, ptr dans insert est NULL :

insert(headptr, data);

Vous définissez ensuite curptr = ptr; , donc curptr est NULL . Il plante alors sur cette ligne:

struct record *headptr = NULL;

Parce que vous essayez d'accéder à la mémoire pointée par curptr , qui est NULL code> à ce stade.

Je suppose que vous vouliez allouer de la mémoire pour headptr avant de le passer à insert . Ou gérez le cas où le pointeur est NULL dans insert.


0 commentaires

0
votes

Si vous passez un pointeur vers une fonction, alors que vous pouvez changer le contenu de ce que le pointeur pointe, vous ne pouvez pas modifier le pointeur, pour ce faire, vous devez passer un pointeur vers le pointeur:

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

struct record{
    int data;
    struct record *nextptr;
};

void insert (struct record** ptr, int value);
void printList(struct record *ptr);

int main() {
    struct record *headptr = NULL;
    for (int i = 0; i < 4; ++i) {
        int data;
        printf("Enter your value");
        scanf("%d", &data);
        insert(&headptr, data);
    }
    printList(headptr);
    return 0;
}

void insert (struct record** ptr, int value) {
    if ( ptr == NULL ) {
    //Do nothing ptr is invalid
        return;  
    } 
    printf("WE ARE IN THE INSERT FUNCTION");
    struct record* curptr = *ptr
                ,* newptr = (struct record *) malloc(sizeof(struct record));
    newptr->data = value;
    //Check curptr isn't NULL
    while(curptr != NULL && value >= (curptr->data)){
        curptr = curptr->nextptr;
    }
    if (curptr == NULL) {
        newptr->nextptr = NULL;
        *ptr = newptr;
    } else {
        newptr->nextptr = curptr;
    }
}

void printList(struct record *ptr){
    while(ptr->nextptr != NULL) {
        printf("%d", ptr->data);
        ptr = ptr->nextptr;
    }
}


2 commentaires

Vous avez raison, mais cela peut être un peu laconique pour le nouveau programmeur C, par exemple " ... pour y parvenir, vous devez passer un pointeur vers le pointeur " - qui permet de passer l'adresse réelle du pointeur d'origine de la fonction appelante dans la fonction appelée afin que tout change fait à l'adresse de pointeur d'origine sont reflétés dans la fonction appelante après le retour de la fonction appelée. Si un pointeur head et ( tail vers le dernier nœud) est conservé, vous pouvez éviter d'itérer pour trouver le dernier nœud à insérer.


Vous rencontrez également des problèmes d'insertion. Afin de faire un "ajout dans l'ordre", vous devez vérifier value> = curptr-> nextptr-> data afin de mettre correctement entre parenthèses les 2 nœuds entre lesquels le nouveau nœud sera inséré.



0
votes

Vous avez deux gros problèmes avec insert . Commencez par passer ptr comme pointeur struct record . Lorsque cela se produit, votre fonction insert reçoit une copie-du-pointeur qui pointe vers le même emplacement en mémoire, mais a une adresse distincte elle-même, très différente de la pointeur passé de main () . Ce que cela signifie n'a pas d'importance ce que vous faites à la copie du pointeur dans insert , ces changements ne seront jamais revus dans main () parce que vous utilisez une copie et ne pas renvoyer autrement une valeur. Pour résoudre ce problème, créez votre paramètre struct record ** et passez l'adresse du pointeur de main () .

Le prochain plus gros problème que vous rencontrez dans insert si vous ne parvenez pas à vérifier si curptr est NULL (comme ce sera le premier appel à insert ) avant de commencer déréférencement curptr - conduisant probablement à un segfault ou à une autre exécution de l'usine Comportement indéfini.

Lors de la création d'une liste liée, vous avez deux conditions de test distinctes que vous devez gérer: p>

  1. Est-ce que j'insère le premier nœud? (si c'est le cas, attribuez simplement `* ptr = newptr); et
  2. toutes les autres insertions vous obligeront à effectuer une itération pour trouver les 2 nœuds appropriés entre lesquels insérer vos données en fonction de la valeur des données .

Vous pouvez gérer les deux cas simplement:

$ ./bin/lltcmpl
Enter your value: 1
Enter your value: 8
Enter your value: 5
Enter your value: 7
 1 5 7 8

$ ./bin/lltcmpl
Enter your value: 2
Enter your value: 1
Enter your value: 4
Enter your value: 3
 1 2 3 4

Dans tout programme que vous écrivez qui alloue de la mémoire, vous devez conserver un pointeur vers le début de chaque bloc alloué il peut donc être libéré lorsque cette mémoire n'est plus nécessaire. Vous voudrez généralement écrire une fonction listfree pour gérer cela pour vous. Vous pouvez écrire quelque chose de simple comme ceci:

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

typedef struct record {
    int data;
    struct record *nextptr;
} rec_t;

void insert (rec_t **ptr, int value);
void printList (rec_t *ptr);
void freelist (rec_t *head);

int main (void) {
    rec_t *headptr = NULL;

    for (int i = 0; i < 4; ++i) {
        int data;
        printf("Enter your value: ");
        scanf("%d", &data);
        insert (&headptr, data);
    }
    printList(headptr);
    freelist (headptr);

    return 0;
}

void insert (rec_t **ptr, int value) 
{
    if ( ptr == NULL ) {
        return;  
    } 

    rec_t *curptr = *ptr,
        *newptr = malloc (sizeof *newptr);  /* don't cast the return */
    if (!newptr) {
        perror ("malloc-newptr");
        return;
    }

    newptr->data = value;
    newptr->nextptr = NULL;

    if (curptr == NULL) {       /* handle new-list case and return */
        *ptr = newptr;
        return;
    }

    if (value < curptr->data) {     /* handle new 1st node */
        newptr->nextptr = curptr;
        *ptr = newptr;
        return;
    }

    /* iterate with curptr until value > curptr->nextptr->data */
    while (curptr->nextptr != NULL && value > curptr->nextptr->data)
        curptr = curptr->nextptr;

    newptr->nextptr = curptr->nextptr;      /* wire new node to next node */
    curptr->nextptr = newptr;               /* wire current to new node */
}

void printList(struct record *ptr)
{
    while (ptr != NULL) {
        printf(" %d", ptr->data);
        ptr = ptr->nextptr;
    }
    putchar ('\n');
}

void freelist (rec_t *head)
{
    while (head) {
        rec_t *victim = head;
        head = head->nextptr;
        free (victim);
    }
}

( remarque: comment le nœud à libérer est enregistré dans un pointeur temporaire victime avant que la liste ne passe au nœud suivant).

En le mettant complètement, vous pouvez faire quelque chose comme ceci:

void freelist (rec_t *head)
{
    while (head) {
        rec_t *victim = head;
        head = head->nextptr;
        free (victim);
    }
}

Exemple d'utilisation / de sortie

    rec_t *curptr = *ptr,
        *newptr = malloc (sizeof *newptr);
    if (!newptr) {
        perror ("malloc-newptr");
        return;
    }

    newptr->data = value;
    newptr->nextptr = NULL;

    if (curptr == NULL) {       /* handle new-list case and return */
        *ptr = newptr;
        return;
    }

    if (value < curptr->data) {     /* handle new 1st node */
        newptr->nextptr = curptr;
        *ptr = newptr;
        return;
    }

    /* iterate with curptr until value > curptr->nextptr->data */
    while (curptr->nextptr != NULL && value > curptr->nextptr->data)
        curptr = curptr->nextptr;

    newptr->nextptr = curptr->nextptr;      /* wire new node to next node */
    curptr->nextptr = newptr;               /* wire current to new node */

Regardez les choses et faites-moi savoir si vous avez des questions.


3 commentaires

C'est faux. Essayez 2 1 3 4 comme entrées, la sortie doit être 1 2 3 4 mais est 2 1 3 4


ajout de if (curptr == * ptr && curptr-> data> newptr-> data) {newptr-> nextptr = curptr; * ptr = newptr; revenir; } avant tandis que dans la fonction insert le corrigerait.


Mes excuses, j'ai omis le chèque sur le 1er nœud. Mise à jour.



0
votes

Tout d'abord, utilisez setbuf (stdout, NULL); si vous voulez que vos impressions soient vidées avant que votre programme ne se termine de manière inattendue.

Deuxièmement, comme d'autres l'ont mentionné, vous accédez à un NULL élément de pointeur dans while (value> = (curptr-> data)) qui provoque le plantage.

Troisièmement, votre insert code > et la logique print est également erronée.

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

struct record{
    int data;
    struct record *nextptr;
};

void insert (struct record **ptr,int value);
void printList(struct record *ptr);

int main() {
    setbuf(stdout, NULL);
    struct record *headptr = NULL;
    for (int i = 0; i < 4; ++i) {
        int data;
        printf("Enter your value");
        scanf("%d", &data);
        insert(&headptr, data);
    }
    printList(headptr);


    return 0;
}
void insert (struct record **head,int value){
    printf("WE ARE IN THE INSERT FUNCTION");
    struct record *newptr = (struct record *) malloc(sizeof(struct record));
    newptr->data=value;
    newptr->nextptr=NULL;
    struct record *curptr=*head;
    struct record *prevcurptr=NULL;

    while(curptr!=NULL && value >= (curptr->data)){
        prevcurptr=curptr;
        curptr=curptr->nextptr;
    }
    if (curptr==NULL){
        if (prevcurptr==NULL) {         
            *head=newptr;
        } else {
            newptr->nextptr=prevcurptr->nextptr;
            prevcurptr->nextptr=newptr;
        }
    }
    else{
        newptr->nextptr=curptr;
        if (prevcurptr==NULL)       
            *head=newptr;
        else
            prevcurptr->nextptr=newptr;
    }

}
void printList(struct record *ptr){
    while(ptr != NULL){
        printf("\n %d", ptr->data);
        ptr=ptr->nextptr;
    }
}


0 commentaires