Discussione Ufficiale Programmiamo con Inforge | Esercitazione 02 in C | Livello base

Una Discussione Ufficiale punta a raccogliere tutte le informazioni su un argomento o un fatto di attualità, con costanti aggiornamenti da parte del creatore e dei partecipanti.

Not an engineer

Moderatore
31 Ottobre 2011
2,715
100
1,204
1,091
Ultima modifica:
main.png


Programmiamo con Inforge | Presentazione

Ad oggi, sul web, si trovano moltissime guide sui vari linguaggi di programmazione e sulle loro molteplici applicazioni. Tuttavia, chi si approccia a queste risorse, non sempre riesce a mettere in pratica ciò che ha appreso. Al fine di limitare queste mancanze, nasce Programmiamo con Inforge.

In questa rubrica potrai scrivere codice per la risoluzione di alcuni problemi legati alla programmazione, mettendo in pratica quanto stai apprendendo dalla teoria oppure mostrando le tue abilità e competenze nel campo dell’informatica.


Partiamo dalle basi del C

In questa guida puoi trovare i testi per studiare e approfondire il C: I migliori libri per imparare e approfondire il C
In questa discussione puoi trovare le risposte alle domande più frequenti su come scrivere codice in C: Frequently asked questions: da dove si parte?


Esercitazione 02 in C | Livello base | [Strutture dati]

Conoscere le strutture dati e saper lavorare su di esse è un aspetto fondamentale della programmazione; con queste entità è possibile organizzare insiemi di dati e compiere una serie di operazioni su di essi.
L'esercitazione si compone di 2 esercizi nei quali ti sarà richiesto di definire una struttura dati che supporti determinate operazioni basilari (è possibile scegliere la struttura che più ti aggrada, ad esempio una lista) come l'inserimento, la ricerca e la cancellazione.



Soluzioni

Per rendere l'esercitazione più interessante, non verrà pubblicata alcuna soluzione! Spetterà a te scrivere la tua versione del codice e pubblicarla in questo thread così che possa essere valutata dai moderatori e dalla community; il modo migliore per imparare!

Conclusioni

Pubblica la soluzione ottimale per risolvere gli esercizi e ricorda che puoi confrontarti con il resto della community in questo thread, chiedere aiuto o aiutare gli altri ;)
 
Ultima modifica:
Avanti ;)

EDIT:
Scusate l'ignoranza ma penso di non aver capito la consegna haha. La funzione insert serve a inserire i dati delle terne?
 
Ultima modifica:
Avanti ;)

EDIT:
Scusate l'ignoranza ma penso di non aver capito la consegna haha. La funzione insert serve a inserire i dati delle terne?

Si, compili i campi della struttura dati definita in C. Ovviamente siete liberi di fare qualsiasi controllo per inserimenti parziali (cosa inserisco nei campi che non voglio modificare? Un valore di default? Un valore semanticamente non corretto? Scegliete voi).
Del tipo se inserisco ("Kode","Inforge",0) evito di aggiornare l'età oppure la aggiorno ugualmente? Siete liberi di decidere :) (Ovviamente io in questo caso opterei di fare dei controlli semantici dato che un if non cambia la complessità se non per tempi costanti, quindi lineari).
 
Ultima modifica:
Pronto a sfornare ignoranza.
Dico subito che non ho la minima idea di come mettere qualcosa di lunghezza variabile in uno struct, quindi da buona capra metto array a lunghezza definita e pace.
Ovviamente continuo a scrivere in c++ essendo, come scritto prima, capra.
 
  • Mi piace
  • Love
Reazioni: Valley e Kode
Ultima modifica:
Posto subito una bozza sbarbina che devo uscire per una mezz'oretta, quando torno spero ci sia già qualcuno che ha distrutto e pestato a sangue questo codice.
p.s. non ricordo come "cancellare" per bene quindi ho semplicemente cambiato in campo vuoto.

C++:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <string>

class elenco
{
        char nome[20]; //ho provato ad usare string per nome e cognome ma mi dà errore, come si può fare? in un main pulito crea e stampa senza problemi
        char cognome[20];
        short eta;
        public:
        void inserisci();
        void visualizza();
        void cancella();
};
void elenco::inserisci()
{
        printf("Inserisci nome: ");
        scanf("%s",&nome);
        printf("Inserisci cognome: ");
        scanf("%s",&cognome);
        printf("Inserisci eta': ");
        scanf("%d",&eta);
     

}
void elenco::visualizza()
{

        printf("\nNome: %s", nome);
        printf("\nCognome: %s", cognome);
        printf("\nEta'': %d", eta);
       
}

void elenco::cancella()
{
    nome"";
    cognome="";
    eta="";
}




main()
{
    elenco r[10];
    int x=-1,c=1;
    while(x!=3)
    {
    printf("1)Inserisci utente\n2)Ricerca utente\n3)Cancella\n4)Inserisci e ordina\n");
    scanf("%d",&x);
        switch(x)
        {
           case 1:
           {       
                r[c].inserisci();
                c++;
                break;
           }
           case 2:
           {
                       int cerca=0;
                       printf("\nInserisci 0>posizione>9 del contatto da cercare:");
                       scanf("%d",&cerca);               
                    r[cerca-1].visualizza();               
                    break;       
           }
           case 3:
           {
                   int num=0;              
                   printf("\nInserisci 0>posizione>9 del contatto da eliminare:");
                   scanf("%d",&num);
                   r[num-1].cancella();
                   break;
           }
           case 4:
           {
            \\questo non ho idea di come farlo, o almeno per il momento non ricordo come far interagire i parametri della funzione e lo struct (sempre se si può)
            break;
           }
        }
    }
}
 
Ultima modifica:
Posto subito una bozza sbarbina che devo uscire per una mezz'oretta, quando torno spero ci sia già qualcuno che ha distrutto e pestato a sangue questo codice.
p.s. non ricordo come "cancellare" per bene quindi ho semplicemente cambiato il contatto in un campo vuoto.

C++:
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
class elenco
{
        char nome[20];
        char cognome[20];
        short eta;
        public:
        void inserisci();
        void visualizza();
        void cancella();
};
void elenco::inserisci()
{
        printf("Inserisci nome: ");
        scanf("%s",&nome);
        printf("Inserisci cognome: ");
        scanf("%s",&cognome);
        printf("Inserisci eta': ");
        scanf("%d",&eta);
      

}
void elenco::visualizza()
{

        printf("\nNome: %s", nome);
        printf("\nCognome: %s", cognome);
        printf("\nEta'': %d", eta);
        
}

void elenco::cancella()
{
    nome"";
    cognome="";
    eta="";
}




main()
{
    elenco r[10];
    int x=-1,c=1;
    while(x!=3)
    {
    printf("1)Inserisci utente\n2)Ricerca utente\n3)Cancella\n4)Esci\n");
    scanf("%d",&x);
        switch(x)
        {
           case 1:
           {        
                r[c].inserisci();
                c++;
                break;
           }
           case 2:
           {
                       int cerca=0;
                       printf("\nInserisci posizione>0 del contatto da cercare:");
                       scanf("%d",&cerca);                
                    r[cerca-1].visualizza();                
                    break;        
           }
           case 3:
           {
                   int num=0;               
                   printf("\nInserisci posizione>0 del contatto da eliminare:");
                   scanf("%d",&num);
                   r[num-1].cancella();
                   break;
           }
           case 4:
           {           
            break;
           }
        }
    }
}
Il case 4 secondo me potrebbe anche non servire in questo caso (certamente non influenza le prestazioni dell'algoritmo). Normalmente si inserisce un controllo di questo tipo quando hai un while che circonda il tuo menù a console, in maniera tale da uscire dal while stesso solamente quando l'utente finisce di utilizzare l'applicazione.
Comunque la consegna chiedeva una sequenza di dimensione variabile e nel tuo caso mi sembra fissa a 10.

Devi implementare un struttura dati LISTA
 
  • Mi piace
Reazioni: Valley
Ultima modifica:
Comunque la consegna chiedeva una sequenza di dimensione variabile e nel tuo caso mi sembra fissa a 10.
Dico subito che non ho la minima idea di come mettere qualcosa di lunghezza variabile in uno struct, quindi da buona capra metto array a lunghezza definita e pace.
Riguardo la seconda parte, praticamente deve ordinare dopo ogni inserimento? *dopo una mezz'ora passata a pensarci, ancora non mi viene in mente niente :V
 
Non vedo l'ora di leggere le vostre soluzioni, è stupendo vedere come vi siano innumerevoli vie di risoluzione e la caccia a quella più ottimizzata è una cosa che adoro. Magari un giorno le facciamo anche per la programmazione web :rulzz:

p.s. postate le soluzioni non siate timidi, c'è solo da imparare! :D
 
Ultima modifica:
Ecco la mia follia con le linked list:
Scusate le funzioni di getString e getInt ma senza usare le STL di C++ mi viene da bestemmiare con la commandline quindi le ho abbozzate in quel brutto modo (per qualche motivo MSVC conosce solo la getline di std).
C:
#include <stdio.h>

typedef struct
{
    char* name;
    char* lastName;
    int age;
} Person;

typedef struct LinkedNode
{
    Person val;
    LinkedNode* next;
} LinkedNode, *PersonList;

char* getString(const char* prompt)
{
    if (prompt != NULL)
        printf("%s ", prompt);

    char* str = (char*)malloc(1024);
    if (str == NULL)
        return NULL;

    do
    {
        fgets(str, 1023, stdin);

    } while (str[0] == '\n');

    int len = strlen(str);
    str[len - 1] = 0;
    return (char*)realloc(str, len);
}

int getInt(const char* prompt)
{
    if (prompt != NULL)
        printf("%s ", prompt);

    int n = 0;
    scanf("%d", &n);
    return n;
}

void free_person(Person& p)
{
    if (p.name != NULL)
        free(p.name);
    if (p.lastName != NULL)
        free(p.lastName);
}

void free_node(LinkedNode* node)
{
    if (node != NULL)
    {
        free_person(node->val);
        free(node);
    }
}

void print_person(Person& p)
{
    printf("Nome: %s \tCognome: %s \tEta': %d\n", p.name, p.lastName, p.age);
}

void print_persons(PersonList& list)
{
    LinkedNode* pNode = list;
    while (pNode != NULL)
    {
        print_person(pNode->val);
        pNode = pNode->next;
    }
}

void insert_person(PersonList& list)
{
    Person p;
    p.name = getString("Inserisci nome:");
    p.lastName = getString("Inserisci cognome:");
    p.age = getInt("Inserisci eta':");

    LinkedNode* node = (LinkedNode*)malloc(sizeof(LinkedNode));
    node->val = p;
    node->next = NULL;

    // sorting by age
    LinkedNode *prevNode, *pNode = list;
    prevNode = NULL;
    while (pNode != NULL)
    {
        if (p.age > pNode->val.age)
        {
            node->next = pNode;

            if (prevNode == NULL)
                list = node;
            else
                prevNode->next = node;
        }
        else if (pNode->next == NULL)
        {
            pNode->next = node;
            break;
        }
        prevNode = pNode;
        pNode = pNode->next;
    }

    if (list == NULL)
        list = node;
}

void find_person(PersonList& list)
{
    LinkedNode* pNode = list;

    char* search = getString("Cerca per Nome o Cognome:");
    int c = 0;

    while (pNode != NULL)
    {
        if (strstr(pNode->val.name, search) != NULL
            || strstr(pNode->val.lastName, search) != NULL)
        {
            print_person(pNode->val);
            c++;
        }
        pNode = pNode->next;
    }
  
    printf("%d risultati trovati\n", c);
    free(search);
}

void delete_person(PersonList& list)
{
    LinkedNode *prevNode, *pNode = list;

    char* name = getString("Nome da eliminare:");
    char* lastName = getString("Cognome da eliminare:");
    int c = 0;

    prevNode = NULL;

    while (pNode != NULL)
    {
        if (strcmp(pNode->val.name, name) == 0
            && strcmp(pNode->val.lastName, lastName) == 0)
        {
            if (pNode == list)
            {
                list = list->next;
                free_node(pNode);
                pNode = list;
            }
            else
            {
                prevNode->next = pNode->next;
                free_node(pNode);
                pNode = prevNode;
            }

            c++;
        }
        prevNode = pNode;
        pNode = pNode->next;
    }

    printf("%d risultati eliminati\n", c);
    free(name);
    free(lastName);
}

typedef void(*cbHandler)(PersonList& list);

typedef struct
{
    const char* Description;
    cbHandler handler;
} Action;

int esercizio2_main()
{
    PersonList list = NULL;

    const Action actions[] = {
        { "Lista persone",      print_persons },
        { "Inserisci persona",  insert_person },
        { "Ricerca",            find_person },
        { "Elimina",            delete_person }
    };

    const int nActions = (sizeof(actions) / sizeof(Action));

    printf("Menu:\n");
    for (int i = 1; i <= nActions; i++)
        printf("- [%d] %s\n", i, actions[i - 1].Description);

    printf("- [0] Esci\n\n");

    int cmd = 0;

    do
    {
        cmd = getInt(">");
      
        if (cmd < 0 || cmd > nActions)
            printf("Comando non valido\n");
        else if (cmd != 0)
            actions[cmd - 1].handler(list);

    } while (cmd > 0);

    return 0;
}

sample.png
 
Ecco la mia follia con le linked list:
Scusate le funzioni di getString e getInt ma senza usare le STL di C++ mi viene da bestemmiare con la commandline quindi le ho abbozzate in quel brutto modo (per qualche motivo MSVC conosce solo la getline di std).
C:
#include <stdio.h>

typedef struct
{
    char* name;
    char* lastName;
    int age;
} Person;

typedef struct LinkedNode
{
    Person val;
    LinkedNode* next;
} LinkedNode, *PersonList;

char* getString(const char* prompt)
{
    if (prompt != NULL)
        printf("%s ", prompt);

    char* str = (char*)malloc(1024);
    if (str == NULL)
        return NULL;

    do
    {
        fgets(str, 1023, stdin);

    } while (str[0] == '\n');

    int len = strlen(str);
    str[len - 1] = 0;
    return (char*)realloc(str, len);
}

int getInt(const char* prompt)
{
    if (prompt != NULL)
        printf("%s ", prompt);

    int n = 0;
    scanf("%d", &n);
    return n;
}

void free_person(Person& p)
{
    if (p.name != NULL)
        free(p.name);
    if (p.lastName != NULL)
        free(p.lastName);
}

void free_node(LinkedNode* node)
{
    if (node != NULL)
    {
        free_person(node->val);
        free(node);
    }
}

void print_person(Person& p)
{
    printf("Nome: %s \tCognome: %s \tEta': %d\n", p.name, p.lastName, p.age);
}

void print_persons(PersonList& list)
{
    LinkedNode* pNode = list;
    while (pNode != NULL)
    {
        print_person(pNode->val);
        pNode = pNode->next;
    }
}

void insert_person(PersonList& list)
{
    Person p;
    p.name = getString("Inserisci nome:");
    p.lastName = getString("Inserisci cognome:");
    p.age = getInt("Inserisci eta':");

    LinkedNode* node = (LinkedNode*)malloc(sizeof(LinkedNode));
    node->val = p;
    node->next = NULL;

    // sorting by age
    LinkedNode *prevNode, *pNode = list;
    prevNode = NULL;
    while (pNode != NULL)
    {
        if (p.age > pNode->val.age)
        {
            node->next = pNode;

            if (prevNode == NULL)
                list = node;
            else
                prevNode->next = node;
        }
        else if (pNode->next == NULL)
        {
            pNode->next = node;
            break;
        }
        prevNode = pNode;
        pNode = pNode->next;
    }

    if (list == NULL)
        list = node;
}

void find_person(PersonList& list)
{
    LinkedNode* pNode = list;

    char* search = getString("Cerca per Nome o Cognome:");
    int c = 0;

    while (pNode != NULL)
    {
        if (strstr(pNode->val.name, search) != NULL
            || strstr(pNode->val.lastName, search) != NULL)
        {
            print_person(pNode->val);
            c++;
        }
        pNode = pNode->next;
    }
 
    printf("%d risultati trovati\n", c);
    free(search);
}

void delete_person(PersonList& list)
{
    LinkedNode *prevNode, *pNode = list;

    char* name = getString("Nome da eliminare:");
    char* lastName = getString("Cognome da eliminare:");
    int c = 0;

    prevNode = NULL;

    while (pNode != NULL)
    {
        if (strcmp(pNode->val.name, name) == 0
            && strcmp(pNode->val.lastName, lastName) == 0)
        {
            if (pNode == list)
            {
                list = list->next;
                free_node(pNode);
                pNode = list;
            }
            else
            {
                prevNode->next = pNode->next;
                free_node(pNode);
                pNode = prevNode;
            }

            c++;
        }
        prevNode = pNode;
        pNode = pNode->next;
    }

    printf("%d risultati eliminati\n", c);
    free(name);
    free(lastName);
}

typedef void(*cbHandler)(PersonList& list);

typedef struct
{
    const char* Description;
    cbHandler handler;
} Action;

int esercizio2_main()
{
    PersonList list = NULL;

    const Action actions[] = {
        { "Lista persone",      print_persons },
        { "Inserisci persona",  insert_person },
        { "Ricerca",            find_person },
        { "Elimina",            delete_person }
    };

    const int nActions = (sizeof(actions) / sizeof(Action));

    printf("Menu:\n");
    for (int i = 1; i <= nActions; i++)
        printf("- [%d] %s\n", i, actions[i - 1].Description);

    printf("- [0] Esci\n\n");

    int cmd = 0;

    do
    {
        cmd = getInt(">");
     
        if (cmd < 0 || cmd > nActions)
            printf("Comando non valido\n");
        else if (cmd != 0)
            actions[cmd - 1].handler(list);

    } while (cmd > 0);

    return 0;
}

Visualizza allegato 50763


Perfetto, uso magistrale delle liste puntate. Se devo dire un modo per migliorare il codice, l'unica cosa che mi viene in mente è quello di inserire una Head al PersonList in modo da piazzarci anche un contatore del numero di Persone e monitorarne il numero, questo perchè se si ha una lista molto grande, risulterebbe difficile capire se l'eliminazione o l'inserimento sono avvenuti con successo o meno (ovviamente il counter lo stampi all'interno della funzione print_persons).
 
@Sax3r28

Perchè non stai "includendo" il namespace, dovresti fare using namespace std; oppure quando definisci la stringa usare std::. Quindi ad esempio std::string nome;. ;)
In C++ per distruggere la memoria allocata esistono i distruttori. Per vedere come si utilizzano https://en.cppreference.com/w/cpp/language/destructor

Poi fai attenzione ad un'altra cosa: stai usando un array di oggetti di tipo elenco, quindi quando elimini una persona... dovresti trovare un modo per "compattare" il tuo array, così da non avere buchi.

Anche nei case 2 e 3, attenzione: dovresti verificare il valore inserito, altrimenti andresti fuori dai limiti dell'array.

Ultima cosa: l'elenco di persone non dovrebbe avere una lunghezza definita. Prova a modificare l'algoritmo così da accettare più di 10 persone. ;)

@JunkCoder
C'è poco da dire, non ho considerazioni da fare, bel lavoro.
 
  • Love
Reazioni: Not an engineer