PROBLEMA Programma in C per trovare numeri di Armstrong

Pubblicità

Hero467

Utente Attivo
Messaggi
695
Reazioni
406
Punteggio
75
Salve a tutti,
ho un programmino in python, che per esercizio sto cercando di programmare in C. Questo programma Python fa uso della parola “in”, che non so come implementare. C’è un corrispettivo in C?

Python:
def check_armstrong(num):
    if str(num) in '1,2,3,4,5,6,7,8,9,0':
        return True
       
    exponent = len(str(num))
    nums = []
   
    for i in range(exponent):
        d_en = int(str(num)[i]) ** exponent
       
        nums.append(d_en)
       
    sum = 0
   
    for i in range(len(nums)):
        sum += int(nums[i])
       
    if sum == num:
        return True
    else:
        return False
       

for i in range(10000000):
    if check_armstrong(i):
        print(i)
    else:
        continue
 
Ultima modifica:
Ciao, se è quella "in" che vedo sul for, si tratta di quello che altri linguaggi chiamano "for each"; comunque no, non esiste in C.

Se ti riferisci a "in" che vedo sull'if... no, discorso analogo, non esiste.

Il primo IF puoi tradurlo semplicemente come:

C:
if(num >= 0 && num <= 9) {
    return 1;
}

Oppure anche...
C:
if(num < 10) { // eventualmente controlla che non sia negativo anche
    return 1;
}

Nel caso dei for si tratta semplicemente di un ciclo da 0 a N.
 
Il primo esempio era quello che mi serviva. Effettivamente non ci avevo pensato.

Andando avanti con la traduzione mi è sorto un altro dubbio: come converto una stringa in un intero? Per il contrario ho usato sprintf, ma non saprei come fare ora…
 
Ecco il codice:
C:
#include <stdio.h>
#include <sting.h>

int main() {

    return 0;
}

int check_armstrong(int num) {
    char snum[100];
    sprintf(snum, "%d", num);
    int exponent = strlen(snum);
    int nums[exponent];
    int sum = 0;
   
    if(strlen(snum) < 10) {
        return 1;
    }
   
    for(int i = 0; i < exponent; i++) {
        int d_en = snum[i] ** exponent;
       
        nums[i] = d_en;
    }
   
    int nums_len = sizeof nums / sizeof nums[0]
   
    for(int i = 0; i < nums_len; i++) {
        sum +=
    }
}

non è eseguibile, visto che mi sono bloccato all’ultima riga, dove avrei bisogno di prendere ricorsivamente ogni elemento di nums e convertirlo in intero, da sommare poi a sum
 
Puoi usare atoi, come dicevo sopra, per convertire da stringa a intero.

Attenzione anche a questo:
C:
        int d_en = snum[i] ** exponent;

in C non esiste, devi usare una funzione apposita per l'elevamento a potenza (pow()). C'è qualche altro errore ma lo vedrai poi compilando.

Mi sa che sti stai complicando un pò la vita, ma ti lascio proseguire sino alla fine. 😁
 
Puoi usare atoi, come dicevo sopra, per convertire da stringa a intero.
Grazie, l’ho implementato

Attenzione anche a questo:
C:
        int d_en = snum[i] ** exponent;

in C non esiste, devi usare una funzione apposita per l'elevamento a potenza (pow()). C'è qualche altro errore ma lo vedrai poi compilando.
ah, sistemo subito. Devo usare qualche libreria particolare o va bene la stdio o la stdlib?

Mi sa che sti stai complicando un pò la vita, ma ti lascio proseguire sino alla fine. 😁
Lo so, ma se no mi annoio. Quindi faccio cose inutili e inutilmente complicate
 
Sono andato avanti, finendo il programma, però mi manda a schermo ogni numero compreso tra 0 e 100 al posto che solo i numeri di Armstrong. Cosa sbaglio?
C:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

int check_armstrong(int num) {
    char snum[100];
    sprintf(snum, "%d", num);
    int exponent = strlen(snum);
    char nums[exponent];
    int sum = 0;
 
    if(strlen(snum) < 10) {
        return 1;
    }
 
    for(int i = 0; i < exponent; i++) {
        char *psnum = snum;
        int d_en = pow(atoi(psnum + i), exponent);
    
        nums[i] = d_en;
    }
 
    int nums_len = sizeof nums / sizeof nums[0];
 
    for(int i = 0; i < nums_len; i++) {
        sum += atoi(nums[i]);
    }
  
    if(sum == num) {
        return 1;
    } else {
        return 0;
    }
}

int main() {

    for(int i = 0; i < 100; i++) {
        if(check_armstrong(i) == 1) {
            printf("%d\n", i);
        }
    }
}

EDIT: Ho appena notato (avrei potuto arrivarci prima, visto il nome) che sprintf produce un output, svelato il mistero. Resta però allora il dubbio, come converto un int in string? Vista l’esistenza di atoi avevo pensato a itoa, ma a quanto pare non è standard
 
Ultima modifica:
Puoi usare sprintf:

C:
int n = 10;
char number[10];

int lenght = sprintf(number, "%d", n);

In number avrai il tuo numero sottoforma di caratteri; il ritorno è la lunghezza, quindi non ti serve fare cose strane.

Inoltre:

C:
    for(int i = 0; i < exponent; i++) {
        char *psnum = snum;
        int d_en = pow(atoi(psnum + i), exponent);
    
        nums[i] = d_en;
    }

Contiene passaggi inutili: puoi direttamente fare snum[i], non serve che effettui quell'operazione; per altro è anche meno efficiente in quanto la fai all'interno di un ciclo (e il tipo di operazione non cambia, potresti farla fuori dal ciclo).

Inoltre, ti complichi la vita per niente: il passaggio da char a int può essere fatto molto più rapidamente:

C:
    for(int i = 0; i < exponent; i++) {
        nums[i] = pow(snum[i] - '0', exponent);
    }

dovrebbe essere corretto a occhio. 😉

Anche l'array nums è un'altra aggiunta di cui non necessiti in realtà: puoi fare direttamente la somma in questo ciclo, senza assegnare a nums ogni singolo valore e poi ciclare sull'array.
Quindi puoi fare tipo:

C:
    for(int i = 0; i < exponent; i++) {
        sum += pow(snum[i] - '0', exponent);
    }

Poi, visto che in C 0 viene valutato come false, e un numero diverso da 0 come true, puoi anche evitare l'ultimo if, trasformando questo:

C:
   if(sum == num) {
        return 1;
    } else {
        return 0;
    }

In un più semplice (e ottimizzato, in quanto rimuovi un if inutile):

C:
return sum == num;


PS. quando avrai terminato, prova anche a completare l'esercizio senza usare le stringhe, ma usando solo gli interi (così, come esercizio).
 
Puoi usare sprintf:

C:
int n = 10;
char number[10];

int lenght = sprintf(number, "%d", n);

In number avrai il tuo numero sottoforma di caratteri; il ritorno è la lunghezza, quindi non ti serve fare cose strane.
Non ho capito, l’output che esce da sprintf sarebbe la lunghezza dell’array? Se si, come faccio a eliminarlo?

Inoltre:

C:
    for(int i = 0; i < exponent; i++) {
        char *psnum = snum;
        int d_en = pow(atoi(psnum + i), exponent);
   
        nums[i] = d_en;
    }

Contiene passaggi inutili: puoi direttamente fare snum[i], non serve che effettui quell'operazione; per altro è anche meno efficiente in quanto la fai all'interno di un ciclo (e il tipo di operazione non cambia, potresti farla fuori dal ciclo).
Avevo provato così al primo tentativo, ma il compilatore mi aveva dato errore, dicendo che si aspettava un puntatore come argomento. Ora funziona però. Boh

Anche l'array nums è un'altra aggiunta di cui non necessiti in realtà: puoi fare direttamente la somma in questo ciclo, senza assegnare a nums ogni singolo valore e poi ciclare sull'array.
Quindi puoi fare tipo:

C:
    for(int i = 0; i < exponent; i++) {
        sum += pow(snum[i] - '0', exponent);
    }
Questa non l’ho proprio capita

PS. quando avrai terminato, prova anche a completare l'esercizio senza usare le stringhe, ma usando solo gli interi (così, come esercizio).
Ci proverò, anche se so già che smatterò molto
 
Non ho capito, l’output che esce da sprintf sarebbe la lunghezza dell’array? Se si, come faccio a eliminarlo?

Non ho capito che intendi con eliminare l'output. Con sprintf ti viene riempito il buffer che passi, che viene usato come output della funzione; ma la funzione restituisce anche un valore, che è il numero di bytes che viene scritto nel buffer.

Avevo provato così al primo tentativo, ma il compilatore mi aveva dato errore, dicendo che si aspettava un puntatore come argomento. Ora funziona però. Boh

Probabilmente non stavi utilizzando le parentesi quadrate, penso.

Questa non l’ho proprio capita

Non ricordo se avevi aperto tu un topic un pò di tempo fa su un algoritmo di crittografia (Cifrario di Vigenere), che usava proprio il valore numerico della codifica ASCII per cifrare il testo (se non eri tu, prova a cercare qui sul forum, lo troverai sicuramente).

C:
#include <stdio.h>

int main()
{
    char number[3];
    int n = 123;
   
    sprintf(number, "%d", n);
   
    printf("%d %d %d\n", number[0], number[1], number[2]);
    printf("%d %d %d\n", (number[0]-'0'), (number[1] - '0'), (number[2]-'0'));

    return 0;
}

Come output restituisce:

Codice:
49 50 51
1 2 3

la prima riga sono i valori ASCII di quei caratteri, ovvero '1', '2', e '3'.
La seconda è il risultato dell'operazione: '1' - '0', '2' - '0' e '3' - '0'.

In C - ma in tutti i linguaggi praticamente - avviene una conversione implicita tra il carattere della codifica ASCII e il rispettivo valore numerico (a livello di "assembly", memorizzi dei numeri).

La codifica la determini usando questa tabella:

asciifull.gif


Come noti '0' corrisponde al valore 48 in decimale, quindi facendo (valore del carattere '1') 49 - 48 ottieni 1.

Ci proverò, anche se so già che smatterò molto

No, sarà probabilmente più semplice vedrai. Ti è sufficiente utilizzare due operatori: divisione, e modulo (il resto, %).
Poi se hai dubbi scrivi pure qui.
 
Non ho capito che intendi con eliminare l'output. Con sprintf ti viene riempito il buffer che passi, che viene usato come output della funzione; ma la funzione restituisce anche un valore, che è il numero di bytes che viene scritto nel buffer.
Appunto, la funzione restituisce un output su console. A me proprio non serve quell’output

Non ricordo se avevi aperto tu un topic un pò di tempo fa su un algoritmo di crittografia (Cifrario di Vigenere), che usava proprio il valore numerico della codifica ASCII per cifrare il testo (se non eri tu, prova a cercare qui sul forum, lo troverai sicuramente).

C:
#include <stdio.h>

int main()
{
    char number[3];
    int n = 123;
 
    sprintf(number, "%d", n);
 
    printf("%d %d %d\n", number[0], number[1], number[2]);
    printf("%d %d %d\n", (number[0]-'0'), (number[1] - '0'), (number[2]-'0'));

    return 0;
}

Come output restituisce:

Codice:
49 50 51
1 2 3

la prima riga sono i valori ASCII di quei caratteri, ovvero '1', '2', e '3'.
La seconda è il risultato dell'operazione: '1' - '0', '2' - '0' e '3' - '0'.

In C - ma in tutti i linguaggi praticamente - avviene una conversione implicita tra il carattere della codifica ASCII e il rispettivo valore numerico (a livello di "assembly", memorizzi dei numeri).

La codifica la determini usando questa tabella:

asciifull.gif


Come noti '0' corrisponde al valore 48 in decimale, quindi facendo (valore del carattere '1') 49 - 48 ottieni 1.
Non ero io, ma ho comunque afferrato più o meno quello che hai scritto. L’unica cosa che non mi è chiara è come ‘1’ - ’0’ possa fare 1 se viene impostato come output decimale. Probabilmente è perché vengo da Python, dove un’operazione del genere darebbe errore
 
Appunto, la funzione restituisce un output su console. A me proprio non serve quell’output

Ma non restituisce alcun output su console. Non è collegata a stdout, viene solo riempito il buffer che tu gli passi, che è poi quello che fai nelle prime righe del tuo programma:

C:
    char snum[100];
    sprintf(snum, "%d", num);
    int exponent = strlen(snum);

solo che non ti serve nemmeno quella "strlen", perchè sprintf ha anche un ritorno che è il numero di bytes scritti, quindi puoi fare:
C:
    char snum[100];
    int exponent = sprintf(snum, "%d", num);

Non ero io, ma ho comunque afferrato più o meno quello che hai scritto. Probabilmente è perché vengo da Python, dove un’operazione del genere darebbe errore

Si ho visto, ho cercato ora il topic, è questo: https://forum.tomshw.it/threads/qualcuno-che-mi-aiuta-capire-un-codice-scritto-in-c.889904/

Non conosco Python, comunque ottieni un risultato simile utilizzando ord(), quindi:

Codice:
number = "123"
list = [ord(ch) for ch in number]
print(list)

// Output
// [49, 50, 51]

L’unica cosa che non mi è chiara è come ‘1’ - ’0’ possa fare 1 se viene impostato come output decimale.

In C (Java, C++, etc etc) puoi effettuare somme e sottrazioni tra dati di tipo char (e anche tra char e int, quindi 'A' + 1 = 'B').
Non ho capito bene cosa ti perplime ma provo a chiarire meglio comunque; se non fai la sottrazione invece di 1 viene stampato 49, che è il valore del carattere '1'. Se sottrai '1' e '0' ottieni il carattere SOH, la cui codifica è il numero 1 (fai sempre riferimento alla tabella ASCII).

Bada bene: i primi 32 caratteri (da 0 a 31) non sono visualizzabili sullo schermo; se invece di usare %d usi %c, la printf cerca di mostrarti un carattere, ma ovviamente non essendo visualizzabile vedrai probabilmente simboli strani.

Prova a dare un occhio al topic che ti ho linkato, ho fatto anche parecchi esempi spiegando il codice riportato dal ragazzo (e preso da quel sito... ecco, non usare quel codice come riferimento per l'apprendimento, conteneva alcuni errori, come vedrai leggendo i vari post).
 
Ho dato un'occhiata, ma in modo veloce e senza capirci molto, però sembra interessante. Con calma lo leggerò meglio.

Ora sono a casa, e ho potuto usare il codice sul mio ide. Ho fatto compilare il codice di prima a gcc, e mi da errore a questo punto:
C:
/home/ricky/Scrivania/Coding/first.c:18:33: warning: passing argument 1 of ‘atoi’ makes pointer from integer without a cast [-Wint-conversion]
   18 |         int d_en = pow(atoi(snum[i]), exponent);
      |                             ~~~~^~~
      |                                 |
      |                                 char

C:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

int check_armstrong(int num) {
    char snum[100];
    sprintf(snum, "%d", num);
    int exponent = strlen(snum);
    char nums[exponent];
    int sum = 0;
 
    if(strlen(snum) < 10) {
        return 1;
    }
 
    for(int i = 0; i < exponent; i++) {
        int d_en = pow(atoi(snum[i]), exponent);
    
        nums[i] = d_en;
    }
 
    int nums_len = sizeof nums / sizeof nums[0];

    for(int i = 0; i < nums_len; i++) {
        sum += nums[i];
    }
 
    if(sum == num) {
        return 1;
    } else {
        return 0;
    }
}

int main() {

    for(int i = 0; i < 100; i++) {
        if(check_armstrong(i) == 1) {
            printf("%d\n", i);
        }
    }
}
 
Pubblicità
Pubblicità

Discussioni Simili

Indietro
Top