[C] Esercizi: sequenza di numeri interi

U

Utente 125751

Ospite
Salve :)

Ho degli esercizi in C che devo svolgere.

1) Esercizio: si scriva in linguaggio C un programma che che stampi sullo schermo una sequenza di numeri interi. compresa tra 0 e 100, in ordine crescente e poi decrescente.


Ho scritto questo:

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


int main()

{
  int num1=0;
  int i;

  printf("\n");


  for (i=0;i<101;i++)
   {       
      printf(" %d",num1);
      num1++;
      /*delay(1000);*/
   }


  printf("\n");
  num1=100;

  for (i=100;-1>i<101;i--)
   {       
      printf(" %d",num1);
      num1--;
      /*delay(1000);*/
   }

  printf("\n\n");


  return 0;

}

La sequenza decrescente non termina più.
Con un secondo compilatore in C, che è online e si basa su Clang, mi dice che c'è un errore in cui la condizione del ciclo for è sempre vera ed in particolare l' errore riguarda tipo il numero "101".

Io quello che ho scritto lo interpreto così: Se il valore di "i" è compreso tra 0 e 100la condizione è sempre vera e quindi viene eseguito il codice all' interno del ciclo for e poi "i--". Se invece "i" ha un valore maggiore di 100 oppure minore di 101 allora la condizione è falsa e non vine eseguito il codice all' interno del cloco e "i--".

Ho fatto questa modifica "for (i=100;0>=i<101;i--)" ma la situazione in output è uguale.

Alla fine mi è venuta in mente questa correzione "
for (i=100;-1<i;i--)" e l' output è finalmente ok.
In seguito ho pensato a questo: "i>-1 && i<101" e funziona.

Alla fine Ipotizzo che in C non è supportato o/e non è permesso questo:"0>=i<101" oppure "-1>i<101". Se è così allora l' importante è saperlo così almeno la prossima volta non farò questo errore.

Invece se lo sostituisco con questo: "i>-1 || i<101", su Pelles C continua a stampare sullo schermo "101" mentre sul compilatore online basato su Clang, continuare a stampare numeri in ordine decrescente. Con entrambi la condizione è sempre vera. "||" significa "OR" e quindi se almeno una delle due condizioni è vera esegue le istruzioni all' interno del ciclo e poi "i--".

2) Esercizio: ripere l' esercizio 1) , però la sequenza di numeri interi dev' essere compresi tra -100 e 0.
Appena è fatto lo posto.

3) Esercizio: Scrivere un programma in C che, senza fare uso di librerie esterne, impari da solo a scrivere una seguenza di numeri interi, compresi tra 0 e 100, prima in ordine crescente e poi in ordine descrente.

4) Esercizio: Ripeter l' esercizio 3) , però la seguenza i numeri interi dev' essere compresi tra -100.

Per quest' ultimi due esercizi ho una mezza idea che poi vi dirò così gentimente mi farete sapere se sono sulla strada giusta oppure no. Prima voglio pensare al 1* e al 2° esercizio, che tra l' altro sono più semplici rispetto agli ultimi due.
 
Ultima modifica da un moderatore:

Ibernato

Utente Èlite
4,328
2,047
OS
Windows 10 Pro / Ubuntu 22.04
Nel secondo for devi mettere i>=0 e hai risolto.
Tra l'altro non ti serve nemmeno la variabile num1 in quanto puoi stampare direttamente i
 
Ultima modifica:

_Achille

Utente Èlite
3,067
725
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
HDD
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
GPU
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
PSU
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
OS
Windows 10 Pro
Oltre al fatto che il main deve avere firma int(void) e non int(), i andrebbe internamente al for, tipofor (int i = 0; ...; ...)
-1<i<101 non ha senso. GCC parla chiaro:
Codice:
prog.cc: In function 'int main()':
prog.cc:7:27: warning: comparison of constant '101' with boolean expression is always true [-Wbool-compare]
    7 |     for (int i = 100; -1<i<101; i++)
      |                       ~~~~^~~~
prog.cc:7:25: warning: comparisons like 'X<=Y<=Z' do not have their mathematical meaning [-Wparentheses]
    7 |     for (int i = 100; -1<i<101; i++)
int main() va bene per C++, non per C.
 

Ibernato

Utente Èlite
4,328
2,047
OS
Windows 10 Pro / Ubuntu 22.04
Oltre al fatto che il main deve avere firma int(void) e non int(), i andrebbe internamente al for, tipofor (int i = 0; ...; ...)
-1<i<101 non ha senso. GCC parla chiaro:
Codice:
prog.cc: In function 'int main()':
prog.cc:7:27: warning: comparison of constant '101' with boolean expression is always true [-Wbool-compare]
    7 |     for (int i = 100; -1<i<101; i++)
      |                       ~~~~^~~~
prog.cc:7:25: warning: comparisons like 'X<=Y<=Z' do not have their mathematical meaning [-Wparentheses]
    7 |     for (int i = 100; -1<i<101; i++)
int main() va bene per C++, non per C.
Vabbè ma non è un errore mettere la dichiarazione di i fuori dal for.
 

_Achille

Utente Èlite
3,067
725
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
HDD
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
GPU
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
PSU
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
OS
Windows 10 Pro
Vabbè ma non è un errore mettere la dichiarazione di i fuori dal for.
Di solito andrebbe evitato, dopo C89. In alcuni applicativi può essere utile ma non è questo il caso
 
U

Utente 125751

Ospite
Esercizi 1) e 2):

C:
#include <stdio.h>

int main()

{ 
  int num1=0;
  int i;
  
  printf("\n");

  for (i=0;i<101;i++)
   {        
      printf(" %d",num1);
      num1++;
   }
  
  printf("\n\n");
  num1=0;

  for (i=0;i>=-100;i--)
   {        
      printf(" %d",num1);
      num1--;
   }
  
  printf("\n\n");
  num1=100;
  
  for (i=100;i>=0;i--)
   {        
      printf(" %d",num1);
      num1--;
   }
  
  printf("\n\n");
  num1=-100;

  for (i=-100;i<=0;i++)
   {
      printf(" %d",num1);
      num1++;
   }
  
  printf("\n\n");


  return 0;
  
}

Per quanto riguarda gli esercizi 3) e 4), pensavo inizializzare una variabile contenente il primo numero e poi faccio generare un numero casuale e salvo i vari risultati. Tra di essi verrà ricavato quello giusto. Il programma dovrà imparare a trovare quello giusto.

Nel secondo for devi mettere i>=0 e hai risolto.

L' ho scritto sopra.

Tra l'altro non ti serve nemmeno la variabile num1 in quanto puoi stampare direttamente i

All' inizio lo avevo fatto però ho letto che potrebbe dare problemi iper quanto riguarda i valori in output. Quindi decisi di modificare il programmare.

Oltre al fatto che il main deve avere firma int(void) e non int(), i andrebbe internamente al for, tipofor (int i = 0; ...; ...)

Non sono informato su C99 e successivi. Sono su C89/C90.

-1<i<101 non ha senso. GCC parla chiaro:

In matematica si. Quello che ho scritto non me lo sono inventato.

'X<=Y<=Z' è diverso da 'X<Y<Z' . Nel primo caso X e Z sono compresi mentre nel secondo caso no.

Facendo ulteriori ricerche ho scoperto che ad es. in C e C++ questa cosa non è supportata. Io non lo sapevo. Ora ho capito chiaramente quello che mi riportava il compilatore online basato su Clang.
 

_Achille

Utente Èlite
3,067
725
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
HDD
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
GPU
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
PSU
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
OS
Windows 10 Pro
All' inizio lo avevo fatto però ho letto che potrebbe dare problemi iper quanto riguarda i valori in output. Quindi decisi di modificare il programmare.
Il programma fa quello che deve fare. Non ha senso ‘sta cosa. Se i è 43 e formatti bene printf in output avrai 43. È alquanto chiaro che sia un esercizio che si risolve con una variabile (contatore) e non più.

Non sono informato su C99 e successivi. Sono su C89/C90.
Il che non ha senso

In matematica si. Quello che ho scritto non me lo sono inventato.
Sì ma C non è un risolutore di disequazioni

'X<=Y<=Z' è diverso da 'X<Y<Z' . Nel primo caso X e Z sono compresi mentre nel secondo caso no.
Sì, e? Ti perdi nel nulla: GCC di certo non perde tempo a scrivere un warning per ogni tipo di disequazione che ti puoi inventare...

Facendo ulteriori ricerche ho scoperto che ad es. in C e C++ questa cosa non è supportata. Io non lo sapevo. Ora ho capito chiaramente quello che mi riportava il compilatore online basato su Clang.
Come molti linguaggi. Non per altro esiste la congiunzione e la disgiunzione. Pure “X<Y<Z” in matematica non è che l’abbreviazione di “Y>X ∧ X<Z”
 

Andretti60

Utente Èlite
6,440
5,091
'X<=Y<=Z' è diverso da 'X<Y<Z' . Nel primo caso X e Z sono compresi mentre nel secondo caso no.

Facendo ulteriori ricerche ho scoperto che ad es. in C e C++ questa cosa non è supportata. Io non lo sapevo. Ora ho capito chiaramente quello che mi riportava il compilatore online basato su Clang.

Dunque, in C praticamente puoi fare TUTTO, questo e' il suo problema. Ecco cosa succede quando scrivi a<i<b:
il compilatore esegui il primo test a<i che ritorna un valore boleano (vero o falso), chiamiamolo 'c' per semplicita' che viene passato al secondo test che diventa quindi c<b, che non ha senso in quanto fa il confronto tra un valore boleano e un valore numerico. Purtroppo il C non ha il tipo bool, il linguaggio C "trasforma" i valori boleani in interi e opera su quelli. Quindi il risultato del test c<b sara' vero o falso a seconda di come il compilatore trascrive la variabile boleana 'c' (non esiste uno standard, quasi sempre Falso viene memorizzato con il numero zero, mentre Vero puo' essere 1 o -1, ma questi sono esempi).
Quindi in effetti PUOI scrivere quel codice, e il compilatore ovviamente ti dara' un warning, ma compilera' lo stesso, il risultato poi sara' imprevedibile.
I linguaggi moderni (incluso i nuovi compilatori C) non ti permettono di scrivere istruzioni di quel tipo, in quanto si accorgono che stai mischiando dati di tipo diverso nella stessa istruzione. In passato esistevano compilatori C con speciali opzioni che permettevano di considerare istruzioni del tipo sopra come errore.

Ti potrai chiedere il perche' di tutto cio'. Il motivo e' che il C non nacque come linguaggio multi-purpose, ma per scrivere un codice operativo (Unix), quindi permetteva di fare ogni cosa senza controllare nulla, tutto era lasciato alla capacita' del programmatore. Questo rendeva il linguaggio estremamente efficace in quanto "saltava" molti test esattamente come avviene nel linguaggio macchina.
Quando io negli anni 80 insegnavo il C, pretendevo che i miei studenti usassero TUTTE le opzioni possibile del compilatore per riconoscere possibili condizioni critiche, e non guardavo neanche il codice a meno che il compilatore non desse alcuna condizione di warning.
 

M1n021

Nuovo Utente
143
68
...Quindi il risultato del test c<b sara' vero o falso a seconda di come il compilatore trascrive la variabile boleana 'c' (non esiste uno standard, quasi sempre Falso viene memorizzato con il numero zero, mentre Vero puo' essere 1 o -1, ma questi sono esempi)...
Su tutto il resto sono completamente d'accordo, ma la suddetta affermazione non mi convince tanto. Facendo delle ricerche in rete ho trovato alcuni frammenti dello standard C che in effetti sembrerebbero avvalorare la tesi secondo la quale un'espressione booleana ritorna sempre 0 se falsa e sempre 1 se vera. D'altronde nella libreria stdbool.h le macro true e false sono definite rispettivamente come 1 e 0.
 
  • Mi piace
Reazioni: Andretti60

Andretti60

Utente Èlite
6,440
5,091
... D'altronde nella libreria stdbool.h le macro true e false sono definite rispettivamente come 1 e 0.
Quella e' parte del compilatore C99, che di fatto definisce il tipo bool, in passato il valore FALSE era definito come zero, e il valore TRUE come qualsiasi altra cosa, tipo
C:
#define    FALSE    0
#define    TRUE    !FALSE
Divertente vero? Ecco perche' nel mio messaggio ho detto (1 o -1, ma questi sono esempi)
Questo permetteva per esempio di testare se un puntatore non fosse nullo con il semplice test if(myPunt), cosa che tra l'altro ho sempre odiato.
Per questa mancanza di formalismo ho sempre considerato il linguaggio C (sia il standard che in maniera minore il ansi) come un cattivo linguaggio per imparare (e insegnare) a programmare, come in genere tutti i linguaggi che implicitamente fanno il casting di operandi.

PS stdbool.h non e' una libreria, solo un include.
 

_Achille

Utente Èlite
3,067
725
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
HDD
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
GPU
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
PSU
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
OS
Windows 10 Pro
Questo permetteva per esempio di testare se un puntatore non fosse nullo con il semplice test if(myPunt), cosa che tra l'altro ho sempre odiato.
La cosa peggiore è che ancora le C++ Core Guidelines consigliano quel costrutto invece di if (ptr != nullptr)
 
  • Mi piace
Reazioni: Andretti60

BAT

Moderatore
Staff Forum
Utente Èlite
22,655
11,440
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
in C/C++ 0 = false e spesso 0.0 = false in qualsiasi standard
invece qualsiasi valore diverso da zero, non importa se positivo o negativo se interpretato come booleano ritorna true
(a meno che non si usa un compilatore che ha opzioni particolari che ti impediscono di farlo).
Perfino Python sotto-sotto interpreta 0 come false e qualunqie altro numero di vero da zero come true, a dispetto di libri, eserciziari e guide varie (provare e credere con la shell).
 
U

Utente 125751

Ospite
Il programma fa quello che deve fare. Non ha senso ‘sta cosa. Se i è 43 e formatti bene printf in output avrai 43. È alquanto chiaro che sia un esercizio che si risolve con una variabile (contatore) e non più.

Mi sono fidato di quello che ho letto in quella discussione. Se la ritrovo la linko o posto uno screen.

Sì, e? Ti perdi nel nulla: GCC di certo non perde tempo a scrivere un warning per ogni tipo di disequazione che ti puoi inventare...

Si. Però non mi serve un warning per ogni tipo di disequazione che mi posso inventare.

Dunque, in C praticamente puoi fare TUTTO, questo e' il suo problema. Ecco cosa succede quando scrivi a<i<b:
il compilatore esegui il primo test a<i che ritorna un valore boleano (vero o falso), chiamiamolo 'c' per semplicita' che viene passato al secondo test che diventa quindi c<b, che non ha senso in quanto fa il confronto tra un valore boleano e un valore numerico. Purtroppo il C non ha il tipo bool, il linguaggio C "trasforma" i valori boleani in interi e opera su quelli. Quindi il risultato del test c<b sara' vero o falso a seconda di come il compilatore trascrive la variabile boleana 'c' (non esiste uno standard, quasi sempre Falso viene memorizzato con il numero zero, mentre Vero puo' essere 1 o -1, ma questi sono esempi).
Quindi in effetti PUOI scrivere quel codice, e il compilatore ovviamente ti dara' un warning, ma compilera' lo stesso, il risultato poi sara' imprevedibile.
I linguaggi moderni (incluso i nuovi compilatori C) non ti permettono di scrivere istruzioni di quel tipo, in quanto si accorgono che stai mischiando dati di tipo diverso nella stessa istruzione. In passato esistevano compilatori C con speciali opzioni che permettevano di considerare istruzioni del tipo sopra come errore.

Ti potrai chiedere il perche' di tutto cio'. Il motivo e' che il C non nacque come linguaggio multi-purpose, ma per scrivere un codice operativo (Unix), quindi permetteva di fare ogni cosa senza controllare nulla, tutto era lasciato alla capacita' del programmatore. Questo rendeva il linguaggio estremamente efficace in quanto "saltava" molti test esattamente come avviene nel linguaggio macchina.
Quando io negli anni 80 insegnavo il C, pretendevo che i miei studenti usassero TUTTE le opzioni possibile del compilatore per riconoscere possibili condizioni critiche, e non guardavo neanche il codice a meno che il compilatore non desse alcuna condizione di warning.

Ti ringrazio per la risposta :) L' ho apprezzata. Mi ha insegnato determinate cose che non sapevo ed in più mi ha fatto riflettere.

Come posso affrontare al meglio "questo suo problema", considerando il mio livello? :)

Se alla fine della "trasformazion"e i valori booleani diventano valori interi allora poi si può fare il confronto con i valori numeri?

Invece Pelles C (uso l' ultima versione) non dava/da nessun warning. Se mi avesse mostrato almeno un warning avrei subito cercato su internet. Ho scoperto l' altro ieri che se imposto il level2 (di default è "level1") su "Warnings" allora mi segnala questo:" warning #2154: Unreachable code". Se invece imposto C99, anzichè C11 oppure C17, non da nessun warning anche se c'è level2 su "Warnings".

Di quei compilatori C con speciali opzioni etc... ci sono anche quelli a 32 bit per Windows? Se si quali sono?

Un' altra opzione potrebbe essere quella di usare Notepad++/Pspad + MinGW o foorse TCC. In questo caso ad es. i warnings dovrebbero fornire un' indicazione più presisa.

Quella e' parte del compilatore C99, che di fatto definisce il tipo bool, in passato il valore FALSE era definito come zero, e il valore TRUE come qualsiasi altra cosa, tipo
C:
#define    FALSE    0
#define    TRUE    !FALSE
Divertente vero? Ecco perche' nel mio messaggio ho detto (1 o -1, ma questi sono esempi)

Per questa mancanza di formalismo ho sempre considerato il linguaggio C (sia il standard che in maniera minore il ansi) come un cattivo linguaggio per imparare (e insegnare) a programmare, come in genere tutti i linguaggi che implicitamente fanno il casting di operandi.

Meno male che almeno FALSE ha un unico valore :)

Magari il Pascal mi può insegnare qualcosa di utile per la programmazione in C.
in C/C++ 0 = false e spesso 0.0 = false in qualsiasi standard
invece qualsiasi valore diverso da zero, non importa se positivo o negativo se interpretato come booleano ritorna true
(a meno che non si usa un compilatore che ha opzioni particolari che ti impediscono di farlo).
Perfino Python sotto-sotto interpreta 0 come false e qualunqie altro numero di vero da zero come true, a dispetto di libri, eserciziari e guide varie (provare e credere con la shell).

Chissà poi cosa succede a questi valori numerici considerando che un processore capisce solo il linguaggio macchina. Non so se in mezzo ci sono i caratteristi ASCII oppure no.
 

Andretti60

Utente Èlite
6,440
5,091
Chissà poi cosa succede a questi valori numerici considerando che un processore capisce solo il linguaggio macchina. Non so se in mezzo ci sono i caratteristi ASCII oppure no.
No, i caratteri ASCII non c'entrano. La codifica ASCII e' quello che e': uno standard per rappresentare caratteri alfanumerici, che assegna ad ogni carattere un numero fisso.

Di fatto hai ragione: nel linguaggio macchina i "tipi" di dati non esistono, esistono solo locazioni di memoria dove sono memorizzati dei numeri. Per esempio nei primitivi linguaggi Assembly i vari test erano SOLO fatti sui numeri, e ti permettevano di "confrontare" due numeri tra loro. Il risultato era proprio la differenza (ossia zero significa che siano uguali). A quel punto era possibile fare un "salto" in una specifica locazione di memoria a seconda del risultato del confronto.

Vediamo un classico esempio di un costrutto if{}else{} in un linguaggio simile al Motorola 68000 (la faccio molto semplice qui):
Codice:
    CMP       #0,A            => confronta la locazione di memoria I con il numero zero
    BLE    LABEL_A        => se e' minore o uguale a zero, salta a LABEL_A
    === codice da eseguire se I e' maggiore di zero
    BRA    FINE            => salta a FINE
LABEL_A:
    === codice da eseguire se A e' minore o uguale di zero
FINE:
Poiche' i processori moderni si sono evoluti, lo sono anche i vari assemblatori (sinceramente non lavoro in Assembly da una vita, non che mi manchi), ma il concetto rimane lo stesso. In un processore tutto cio' che esiste e' una valore numerico in una locazione di memoria, spetta a noi cosa metterci e come interpetrarlo. Incluso i numeri di una codifica ASCII.
Post unito automaticamente:

Come posso affrontare al meglio "questo suo problema", considerando il mio livello? :)
Bella domanda.
Studiare il linguaggio C piu' in dettaglio non guasta, o passare a un linguaggio piu' evoluto dove esista un vario insieme di tipi di dati il cui uso venga rinforzato dal compilatore. Se usi il C, controlla il settaggio e metti i livelli di warning a manetta (e' quello che pretendevo dai miei studenti)
 

M1n021

Nuovo Utente
143
68
Quella e' parte del compilatore C99, che di fatto definisce il tipo bool, in passato il valore FALSE era definito come zero, e il valore TRUE come qualsiasi altra cosa, tipo
C:
#define    FALSE    0
#define    TRUE    !FALSE
Divertente vero? Ecco perche' nel mio messaggio ho detto (1 o -1, ma questi sono esempi)
Questo permetteva per esempio di testare se un puntatore non fosse nullo con il semplice test if(myPunt), cosa che tra l'altro ho sempre odiato.
Per questa mancanza di formalismo ho sempre considerato il linguaggio C (sia il standard che in maniera minore il ansi) come un cattivo linguaggio per imparare (e insegnare) a programmare, come in genere tutti i linguaggi che implicitamente fanno il casting di operandi.

PS stdbool.h non e' una libreria, solo un include.
Che scrivere del "buon" codice renda tutto più chiaro e permetta di evitare inutili rogne è fuor di dubbio!

Riguardo alla seconda macro che hai postato, abbiamo che:
TRUE = !FALSE = !0
bisogna quindi vedere cosa dice lo stesso standard riguardo all'operatore NOT.
Lo standard C99 al riguardo dice:
The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int
In tal caso la suddetta macro si riduce semplicemente a
C:
#define TRUE 1

In ogni caso, premesso che non sono un esperto dei vari standard che si sono succeduti nel tempo, quello che intendevo dire è che attualmente l'espressione 2<3>0 non credo affatto che possa essere definita imprevedibile in quanto dovrebbe risultare sempre vera.
 

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili