[C]Matrice 4x4

frab1
ho scritto un piccolo programma che dovrebbe stamparmi una matrice 4x4 cosi:
(0,1,2,3)
(1,2,3,4)
(2,3,4,5)
(3,4,5,6)

ma non capisco perchè non funzioni... :oops:

#include <stdio.h>

main()
{
	int n=4;
	int m=4;
	int matrice [n][m];	//n: righe, m:colonne
	int i;
	int j;

for (i=0;i<m;i++)
{
	for (j=0;j<n; j++)
	{
		printf("%d",matrice[i][j]);
	}
	printf("\n");
}
}


qualche dritta?

Risposte
frab1
ok, credo sia ora di seguire una guida al C piu' efficiente...grazie TeM!
:-)

nessuno.nobody
Mi permetto di farti qualche appunto, in modo che tu possa scrivere codice C migliore ;)

La funzione main, dev'essere ritornare un valore intero. Quindi la sua definizione dev'essere
int main

Se non ti servono parametri da riga di comando, NON lasciare le parentesi del main vuote, ma specifica questa tua necessià. (Per il compilatore C++ int main() e int main(void) sono uguali, per quell C no.)

Quindi
int main(void)

Il valore di ritorno, di norma è zero, ma se vuoi fare codice portabile dovresti usare la macro EXIT_SUCCESS (presente in stdlib.h), quindi alla fine del main
return EXIT_SUCCESS;


Come ha giustamente detto TeM, al tuo programma manca l'inizializzazione della matrice.
In particolare, in C, devi prendere come regola d'oro quella di inizializzare SEMPRE le variabili, perché non vengono inizializzate automaticamente e quindi hanno un valore indefinito.

Se devi semplicemente andare a capo, non usare la printf("\n"), che è uno spreco inutile di risorse, usa la putchar('\n');

Non usare mai system per mettere in pausa il processo, perché non rende il tuo codice portabile.
Usa:
while(getchar() != '\n');


Quindi per completezza, ti riporto il codice fatto nella maniera più portabile possibile
#include <stdio.h>
#include <stdlib.h>

#define n 4
#define m n
int main(void)
{
    int i, j, matrice [n][m];

    for (i=0; i<n; ++i) {
        for (j=0; j<m ; ++j) {
            matrice[i][j] = i + j;
        }
    }

    for (i=0; i<m; ++i) {
        for (j=0; j<n; ++j) {
            printf("%d ",matrice[i][j]);
        }
        putchar('\n');
    }

    puts("Premi invio per terminare");

    while(getchar() != '\n');

    return EXIT_SUCCESS;
}


Spero che questi consigli ti aiutino!

frab1
"nessuno.nobody":

Se non ti servono parametri da riga di comando, NON lasciare le parentesi del main vuote, ma specifica questa tua necessià. (Per il compilatore C++ int main() e int main(void) sono uguali, per quell C no.)
Quindi
int main(void)


ok, sostanzialmente quindi quando non uso delle scanf metto il void tra parentesi? Se invece passo parametri da linea di comando? Le parentesi vuote?

"nessuno.nobody":
Come ha giustamente detto TeM, al tuo programma manca l'inizializzazione della matrice.
In particolare, in C, devi prendere come regola d'oro quella di inizializzare SEMPRE le variabili, perché non vengono inizializzate automaticamente e quindi hanno un valore indefinito.


Quindi non basta definirle nel main come int? Se non uso la #define funziona comunque, per quale motivo? La guida online ancora non mi ha spiegato l'uso della define...

"nessuno.nobody":
Se devi semplicemente andare a capo, non usare la printf("\n"), che è uno spreco inutile di risorse, usa la putchar('\n');


No anche a me sembrava superfluo, infatti solitamente includo l' "a capo" nelle printf precedenti...la putchar legge un carattere per volta e lo stampa a video...in questo caso non riesco a comprenderne il funzionamento :cry:

"nessuno.nobody":
Non usare mai system per mettere in pausa il processo, perché non rende il tuo codice portabile.
Usa:
while(getchar() != '\n');


quindi sostanzialmente cosi termino il programma da terminale? è questo il senso?

"nessuno.nobody":
Quindi per completezza, ti riporto il codice fatto nella maniera più portabile possibile
#include <stdio.h>
#include <stdlib.h>

#define n 4
#define m n
int main(void)
{
    int i, j, matrice [n][m];

    for (i=0; i<n; ++i) {
        for (j=0; j<m ; ++j) {
            matrice[i][j] = i + j;
        }
    }

    for (i=0; i<m; ++i) {
        for (j=0; j<n; ++j) {
            printf("%d ",matrice[i][j]);
        }
        putchar('\n');
    }

    puts("Premi invio per terminare");

    while(getchar() != '\n');

    return EXIT_SUCCESS;
}


Spero che questi consigli ti aiutino!

tutto chiaro, non sapevo che le variabili dello stesso tipo si potessero dichiarare tutte insieme, la "puts" come funziona? Che differenza ha dalla printf? Grazie mille per i tuoi preziosi consigli!!

frab1
ho provato a snellire un po' il codice, mettendo "compilazone" e stampa della matrice tutti nello stesso ciclo

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

int main(void)
{
	int n=4;
	int m=4;
	int i, j, matrice [n][m];	//n: righe, m:colonne

for (i=0;i<m;i++) {
	for (j=0;j<n; j++) {
		matrice[i][j]=i+j;		
		printf("%d",matrice[i][j]);
	}
	printf("\n");
}
	return EXIT_SUCCESS;
}


funziona ma non ho usato la DEFINE... :?:

vict85
"nessuno.nobody":
Il valore di ritorno, di norma è zero, ma se vuoi fare codice portabile dovresti usare la macro EXIT_SUCCESS (presente in stdlib.h), quindi alla fine del main
return EXIT_SUCCESS;


Lo standard C11 (e penso precedenti[nota]Non ho guardato.[/nota]) non sono completamente d’acccordo con te.

"n1570":
5.1.2.2.3 Program termination

If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified.


7.22.4.4 The exit function

[...]

Finally, control is returned to the host environment. If the value of status is zero or
EXIT_SUCCESS, an implementation-defined form of the status successful termination is
returned. If the value of status is EXIT_FAILURE, an implementation-defined form
of the status unsuccessful termination is returned. Otherwise the status returned is
implementation-defined.


Come quindi puoi notare usare 0, o addirittura omettere il return statement alla fine del main è assolutamente portabile e standard e il comportamente di exit(0) è assicurato essere equivalente a exit(EXIT_SUCCESS). Quindi non c'è nessuna ragione di portabilità per preferirlo. La scrittura EXIT_SUCCESS è semplicemente più chiara, specialmente se si usa nello stesso file anche EXIT_FAILURE. Ma alle volte si scrivono programmi stupidi che non hanno un vero e proprio concetto di successo/insuccesso.

"nessuno.nobody":
Se devi semplicemente andare a capo, non usare la printf("\n"), che è uno spreco inutile di risorse, usa la putchar('\n');


L'I/O è così lento che dubito che la differenza di performance tra printf("\n"); puts(""); o putchar('\n'); si noti a livello di utente.

"nessuno.nobody":
Non usare mai system per mettere in pausa il processo, perché non rende il tuo codice portabile.
Usa:
while(getchar() != '\n');


O ancora meglio non usare niente di tutto ciò. Cambia IDE e fai partire il programma usando le impostazioni per "Applicazioni Console". Per esempio su visual studio basta far partire con Ctrl+F5 mentre su Code::blocks è automatico (si gestisce dalle opzioni di build selezionando console application). Anche perché se tu facessi partire la funzione da linea di comando tutti questi "trucchetti" sarebbero solo fastidiosi.
L'unico motivo per cui il tuo metodo è migliore di usare system è per come funziona system. Anche perché quello che vuoi fare è chiamare PAUSE dopo la chiamata della funzione e non dentro, cosa che un IDE serio sa fare.

vict85
"frab":
ho provato a snellire un po' il codice, mettendo "compilazone" e stampa della matrice tutti nello stesso ciclo

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

int main(void)
{
	int n=4;
	int m=4;
	int i, j, matrice [n][m];	//n: righe, m:colonne

for (i=0;i<m;i++) {
	for (j=0;j<n; j++) {
		matrice[i][j]=i+j;		
		printf("%d",matrice[i][j]);
	}
	printf("\n");
}
	return EXIT_SUCCESS;
}


funziona ma non ho usato la DEFINE... :?:


Era meglio prima. È spesso meglio dividere componenti così diversi. Quindi non mettere inizializzazione e stampa nello stesso ciclo a meno che non serva per scopi di debug.

L'uso dei #define serve solo a non tenerti n e m in memoria, utile fino ad un certo punto ma comune quando si scrive in C (in C++ si tende a usare variabili const al loro posto). Non metterli né costanti né definiti con un #define è una cattiva scelta perché potresti sovrascrivere quei valori durante il codice perdendo informazioni importanti.

Definire tutte le variabili all'inizio del blocco non è più necessario e puoi definire i e j nel for. Io sinceramente trovo sia sempre meglio farlo. Hai comunque dimenticato di mettere uno spazio tra i vari elementi stampati rendendo la lettura decisamente più difficile.

Inoltre i va da 0 a n-1 e j va da 0 a m-1, non il contrario.

frab1
"vict85":

Era meglio prima. È spesso meglio dividere componenti così diversi. Quindi non mettere inizializzazione e stampa nello stesso ciclo a meno che non serva per scopi di debug.

OK allora li separo, grazie.

"vict85":
L'uso dei #define serve solo a non tenerti n e m in memoria, utile fino ad un certo punto ma comune quando si scrive in C (in C++ si tende a usare variabili const al loro posto). Non metterli né costanti né definiti con un #define è una cattiva scelta perché potresti sovrascrivere quei valori durante il codice perdendo informazioni importanti.

Prendero' la buona abitudine di usare i #define.


"vict85":
Definire tutte le variabili all'inizio del blocco non è più necessario e puoi definire i e j nel for. Io sinceramente trovo sia sempre meglio farlo. Hai comunque dimenticato di mettere uno spazio tra i vari elementi stampati rendendo la lettura decisamente più difficile.

Cioè scrivendo:
#define m
#define n

posso omettere
int m;
int n;


??

vict85
O usi i #define oppure definisci delle variabili. Se metti prima i define dovrebbe tra l'altro darti errore, se lo metti dopo stai offuscando le variabili e probabilmente non ti da neanche un warning. Comunque non farlo.

Comunque intendevo dire che puoi evitare di scrivere
int i, j;
e scrivere
for(int i=0; i<n; ++i)
nel for. Comunque è solo una opinione stilistica, se vuoi continuare come prima non ci sono problemi.

frab1
Capito, grazie. :-)

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.