Partage
  • Partager sur Facebook
  • Partager sur Twitter

Début du programme sur C

opération sur C

14 janvier 2020 à 17:57:26

Bonjour tout le monde, 

Je crée ce sujet car j'ai un problème avec mon programme, je ne suis qu'au tout début de la programmation en C. Je souhaite faire faire une opération à l'ordinateur : 5+3 (évidemment nous connaissons tous la réponse le but est de simplement tester le programme, qui en l'occurrence, ne marche pas) voici mon programme :

#include <stdio.h>

#include <stdlib.h>

{

int resultat=0;

Resultat = 5+3;

printf(       "5+3 = %d")

  return 0;

}

Merci pour vos réponses !

  • Partager sur Facebook
  • Partager sur Twitter
14 janvier 2020 à 18:12:05

Hello,

Dans le printf(), tu donnes le format.... mais pas la valeur à afficher. Aussi, pas besoin de stdlib dans ce programme.

Et, stp, 

-
Edité par edgarjacobs 14 janvier 2020 à 18:12:56

  • Partager sur Facebook
  • Partager sur Twitter

On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

14 janvier 2020 à 18:15:48

bonjour 

la machine sait que d est le drapeau d'un type int mais dans votre code vous ne lui dites pas à quelle variable appartient ce type

 sans trop chercher à tout vous dire , relisez bien votre cours

 et n'oubliez pas le ; à la fin d'une instruction ici printf();  

  • Partager sur Facebook
  • Partager sur Twitter
14 janvier 2020 à 18:37:57

Salut,
Je ne vois pas ton 'main' dans le code (EJ me dira que je ne vois rien de toute façon ...)
Je ne sais pas pourquoi tout le monde s'entête à ajouter stdlib.h à toutes les sauces.
Quand on étudie des fonctions comme 'printf', il faut regarder les en-têtes qui sont requises et ne pas ajouter plus.
Je suis contre l'idée d'initialiser des variables comme 'resultat' si on doit leur donner une valeur juste après.
(c'est ce qu'on enseigne dans les cours, mais c'est le mauvais moyen d'éviter les bugs)
Puis-je te demander de faire un copier-coller de ton code au lieu de le recopier manuellement comme ça semble le cas ici.
On aura la version exacte de ce que tu as testé.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

14 janvier 2020 à 19:00:08

Bonjour PierrotLF

il débute et dans le cours il a stdlib qui est déjà placé dans le code

les explications viennent plus loin dans son cours

  • Partager sur Facebook
  • Partager sur Twitter
14 janvier 2020 à 19:29:30

PierrotLeFou a écrit:

Je suis contre l'idée d'initialiser des variables comme 'resultat' si on doit leur donner une valeur juste après.

Tu vas à la fois t'attirer des foudres et des sympathies (dont la mienne): je trouve idiot d'écrire

int i=0;

....

for(i=0; etc

Après tout, pourquoi ne pas écrire int i=666 en ligne 1 ?

À part ça, bien vu :) pour l'absence du main()



-
Edité par edgarjacobs 14 janvier 2020 à 19:36:46

  • Partager sur Facebook
  • Partager sur Twitter

On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

15 janvier 2020 à 1:47:23

@DominiqueSicilia;
Je ne sais pas si c'est le cours de Mathieu Nebra ...  Mais justement les débutants n'utilisent pas de fonction complexes ou exotiques.
La plupart du temps, ils n'ont besoin que de stdio.h pour les entrées-sorties standard.
Je ne sais pas ce qu'on leur explique par la suite, mais le prof doit insister sur le fait que le fichier .h contient les définitions associés à la fonction en question.
Et que ce n'est pas une décoration pour faire bien.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

15 janvier 2020 à 11:35:16

Il y a aussi le fait que que quand on crée un nouveau projet sous Code::blocks le code inséré automatiquement l'inclus :

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

int main()
{
    printf("Hello world!\n");
    return 0;
}



  • Partager sur Facebook
  • Partager sur Twitter
15 janvier 2020 à 11:38:51

Et donc inclure <stdlib.h> est inutile ... pour le moment.

Mais cela n'apporte aucun problème de lisibilité.
Elle finira par devenir utile si le projet devient un peu plus conséquent. (et c'est déjà prêt)


Pour d'autre include j'aurais été d'accord.

Sinon on peut prendre la même argumentation et dire : pourquoi inclure tout stdio.h alors qu'on utilise que printf ?
Autant marquer le prototype de printf et pas besoin d'inclure !

int printf ( const char * format, ... );
 
int main(void)
{
	printf("Hello world !\n");
	return 0;
}


Et la réponse que j'ai faite pour stdlib.h fonctionne aussi ici.
Si j'ai besoin d'une autre fonctionnalité de stdio (scanf?) , et bien avec l'include ... c'est déjà fait et on ne se prend pas la tête.

De plus , les constante EXIS_SUCCESS et EXIT_FAILURE sont dans stdlib.h
et si on voulait vraiment faire un code ultra propre il faudrait , à la fin du main , faire un return EXIT_SUCCESS; et donc , il faudrait toujours inclure stdlib, même pour un hello world...

Mon avis est que mettre stdio et stdlib pour chaque projet lorsque l'on débute, permet de mieux se focaliser sur les bases du langage (variable, structure conditionnelle , pointeurs,structure,fonction, etc..).


Pour le int i=0 

int i;
//...
for(i=0;///...

ou bien 

int i=0
//...
for(;//...

J'ai une préférence pour la seconde. (mais les deux sont corrects), mais faire une initialisation inutile (qui sera géré par le compilateur), est-ce un problème en soit ? Objectivement je ne sais pas. Personnellement, je m'en fiche, ça ne gène pas la lecture du code.

Sachant que la personne débute et n'a pas encore l'habitude d'utiliser printf... pas besoin de lui prendre la tête sur des petits détails sans conséquences.

Be gentle, it's his first time ! ;) 

  • Partager sur Facebook
  • Partager sur Twitter
15 janvier 2020 à 12:49:57

PierrotLeFou a écrit:

Je suis contre l'idée d'initialiser des variables comme 'resultat' si on doit leur donner une valeur juste après.
(c'est ce qu'on enseigne dans les cours, mais c'est le mauvais moyen d'éviter les bugs)

 .

Entièrement d'accord ! De plus, je trouve qu'on a trop souvent tendance à faire croire qu'initialiser une variable consiste à lui donner la valeur 0. Ben non, parfois la valeur initiale pertinente (lorsqu'il y en a une) est non nulle. Par exemple dans un calcul de factorielle il faut initialiser à 1, surtout pas à 0...

-
Edité par robun 15 janvier 2020 à 12:50:45

  • Partager sur Facebook
  • Partager sur Twitter
15 janvier 2020 à 14:46:04

C'est vrai qu'on peut devenir maniaque à vouloir enlever du code soi-disant inutile.
Un autre argument serait que si la difinition officielle change, le code devient moins portable.
Pour le for(; ...), s'il est au début, ça va. Autrement je ne suis pas d'accord.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

15 janvier 2020 à 15:10:19

Devenir maniaque c'est un effet pervers du langage :D 

Je n'ai pas compris ce que tu entends par "si la définition officielle change" :euh:

  • Partager sur Facebook
  • Partager sur Twitter
15 janvier 2020 à 16:17:29

Bonjour

en ce qui me concerne si je place un

for (i=0;)

dans une fonction pour utiliser un printf c'est que j'ai l'intention de le supprimer plus tard

si je le supprime plus tard et que j'oublie de supprimer l'initialisation de i j'aime pas trop laisser un 

int i;  

en fait la fonction printf ne me sert strictement à rien quand le projet est fini  

 mais c'est vrai que quand tout est fini on termine de supprimer tous les trucs inutiles mais bon ...



  • Partager sur Facebook
  • Partager sur Twitter
15 janvier 2020 à 17:08:16

@neuneutrino:
En fait je me suis mal exprimé, ce n'est pas forcément le cas pour stdio.h, mais il y a des headers qui sont différents d'un système à l'autre.
Et si on mettait ses propres définitions, on pourrait avoir des problèmes de portabilité, entre autres.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

16 janvier 2020 à 18:19:45

Je programme en C sur Code:: Blocks pour ceux qui pourraient se poser la question... Mais d'après, est-ce le bon outil?
  • Partager sur Facebook
  • Partager sur Twitter
16 janvier 2020 à 18:36:54

Code:: Blocks est un bon outil.
Je ne l'utilise pas, c'est pourquoi j'ai pensé que stdlib.h avait été placé manuellement.
On peut toujours le mettre en commentaire. Comme ça, il n'est pas perdu.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

16 janvier 2020 à 20:04:20

Après le problème du stdlib.h, n'est pas le principal problème de ton code !

Comme on te l'a dit plus haut les principaux problème sont : tu n'as pas de fonction main dans ton code, l'utilisation de la fonction printf n'est pas correcte et une instruction doit se terminer par un point virgule !

  • Partager sur Facebook
  • Partager sur Twitter
17 janvier 2020 à 8:19:50

Et quand on declare résultat, on lui met pas une majuscule après.

Mais le point important c'est que la compilation produit des MESSAGES qui sont UTILES et intéressants.

Ils donnent des indications précises sur l'erreur rencontrée. Il faut les lire, pas se contenter de "zut y a des trucs en rouge".

-
Edité par michelbillaud 17 janvier 2020 à 8:23:38

  • Partager sur Facebook
  • Partager sur Twitter
18 janvier 2020 à 22:54:25

Justement lorsque je fais des erreurs sur mon code, il y a seulement un petit carré rouge sur le coté, mais y a-t-il une possibilité de connaître ce qui est faux dans la ligne?
  • Partager sur Facebook
  • Partager sur Twitter
19 janvier 2020 à 0:02:13

Salut,

Michel t'a donné la réponse. Si tu es choqué par quelqu'un qui écrit "cheuval" au lieu de "cheval", tu vas quand même comprendre le sens de la phrase. L'ordi, enfin, le compilo, lui, si tu déclares "resultat" et que tu affectes "Resultat" sans déclaration en amont, il va pas chercher à comprendre, il va t'insulter.

En clair, tu déclares "resultat", puis tu affectes "Resultat" qui est inconnu au bataillon.

  • Partager sur Facebook
  • Partager sur Twitter
19 janvier 2020 à 0:11:12

Oui mais il y a forcément un message d'erreur quelque part. Peut-être faut-il cliquer sur le carré rouge, je ne sais pas, mais il y a forcément un message d'erreur, il faut juste le trouver. (Si quelqu'un connaît Code::Blocks, il pourra indiquer où il se trouve.)
  • Partager sur Facebook
  • Partager sur Twitter
19 janvier 2020 à 0:20:39

De mémoire, par défaut, il y a un emplacement pour les erreurs. Je soupçonne CV de faire une fixation visuelle sur le code-source en plein milieu de l'écran de CB. Si ça n'a pas changé, il lui suffit juste de... baisser les yeux d'environ 17°.
  • Partager sur Facebook
  • Partager sur Twitter
19 janvier 2020 à 7:11:49

Autrefois, il y avait des langages où on n'était pas obligé de déclarer les variables.

En Fortran, la "règle IJKLMN" disait que quand un nom de variable commençait par une de ces lettres, la variable était de type INTEGER, et les autres REAL. Et voilà, magique.

Ça allait bien tant qu'on faisait des programmes de gorets de quelques dizaines de lignes, à tendance matheuse sur des entiers i, j et des vecteurs v1 et v2. Mais quand on s'est mis à utiliser des noms de variables plus longs, c'était la cata avec les fautes de frappe.

Finalement la déclaration implicite, sous prétexte de simplifier la vie, était une très mauvaise idée.

Donc maintenant, on déclare ce qu'on utilise, et le compilateur nous signale gentiment qu'on s'est trompé, ce qui arrive forcément. Ce ne sont pas des insultes, mais une aide pour écrire des programmes qui marchent. Le compilateur est votre ami.

-
Edité par michelbillaud 19 janvier 2020 à 7:13:00

  • Partager sur Facebook
  • Partager sur Twitter
19 janvier 2020 à 7:36:04

C'était encore pire en Fortran si on confondait les O avec les zéro et les UN avec les 'i'.
 D0 I=1,10
n'était pas forcément une erreur (sur de mauvais compilateurs).
Surtout que les espaces n'étaient pas significatifs.
Quand je faisais de la consultation, j'en ai vu beaucoup du genre.
Avec les cartes perforées, c'était facile de faire la différence. Les chiffres n'avaient qu'une perforation par colonne.
C'est drôle, je n'ai jamais considéré les warning ou les erreurs comme des insultes qu'on me disait.
J'ai connu quelqu'un qui s'appelait Réal Brodeur et qui donnait son nom sans commentaire:
 REAL BRODEUR
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

19 janvier 2020 à 11:44:40

Salut,

Pour ce qui est de savoir si code::blocks est un bon outil, tu vas avoir des réponses relatives à chacun. Dans l'absolu, le bon outil est celui dont tu sais te servir correctement et qui correspond à tes attentes.

Pour afficher les résultats de compilation, c'est la touche F2 puis l'onglet "Build messages". Le compilo y affiche le type de l'erreur (ou de l'alerte), il suffit de cliquer dessus pour qu'il t'emmène à la ligne concernée. à toi de relire la ligne et de trouver l'erreur correspondante.

Quant aux initialisations à la déclaration, je suis partisan de ne pas déclarer une variable tant qu'on en a pas besoin, de préférence avec une valeur "utile", et pour aller plus loin,  le faire localement autant que possible.

Je ne ferais pas :

int i,
    resultat;

for(i=0; i<5, i++)
{
   resultat = 2*i;
   ...;
}

mais :

for (int i=0; i<5; i++)
{
  int resultat = 2*i;
  ...;
}

Après, si tu veux t'acharner à coder en strict C89, on ne peut blâmer personne de vivre encore au millénaire dernier... Mais bon, si tu tiens à rester en 1989, tu vas être obligé d'écouter Bernard Minet chanter "Dis-moi Bioman", ça ne fait pas envie o_O.

Bonne continuation.

  • Partager sur Facebook
  • Partager sur Twitter

Bonhomme !! | Jeu de plateforme : Prototype.

19 janvier 2020 à 13:39:44

Une petite question un peu hors-sujet à propos des déclarations de variables à l'extérieur du bloc où elles peuvent être utiles...

Mettons que j'ai un programme qui réalise des millions de calculs en chaîne, dans lesquels il y a une permutation (c'est exemple simple d'endroit où on va avoir besoin de déclarer une variable locale) :

void permuter(double* px, double* py)
// permute deux nombres passés par adresse
{
    double tmp ;
    tmp = *px ;
    *px = *py ;
    *py = tmp ;
}

et tout ça est appelé en permanence lors de gros calculs.

Question : est-ce que la création de la variable temporaire 'tmp' est quelque chose qui prend autant de temps que, par exemple, une opération ?

Si oui, ça voudrait dire qu'on aurait intérêt à déclarer 'tmp' en dehors de la boucle qui appelle la fonction, afin qu'elle soit créée une seule fois.

--> Tiens, du coup je vais essayer...

VERSION 1 : variable temporaire dans la fonction :

void permuter(double* px, double* py)
{
    double tmp ;
    tmp = *px ;
    *px = *py ;
    *py = tmp ;
}

int main(void)
{
    double a = 2.5, b = 25000.0 ;
    for (int i = 0 ; i < 1000000000 ; i++)
        permuter(&a, &b) ;
    return 0 ;
}

Exécution du programme :

robun@Ordi:~ > time truc
real    0m4.857s
user    0m4.852s
sys     0m0.000s

VERSION 2 : variable temporaire déclarée comme globale :

double tmp ;

void permuter(double* px, double* py)
{
    tmp = *px ;
    *px = *py ;
    *py = tmp ;
}

int main(void)
{
    double a = 2.5, b = 25000.0 ;
    for (int i = 0 ; i < 1000000000 ; i++)
        permuter(&a, &b) ;
    return 0 ;
}
Exécution du programme :
robun@Ordi:~ > time truc
real    0m4.387s
user    0m4.380s
sys     0m0.000s
On gagne quand même quasiment une demi-seconde, plus de 10 % du temps. Mine de rien, ce n'est pas négligeable...



  • Partager sur Facebook
  • Partager sur Twitter
19 janvier 2020 à 15:03:11

Re,

Une demi-seconde d'écart sur un milliard d'appels, ça reste peu. Je comprend parfaitement qu'il puisse exister des cas d'applications pour lesquelles ces 10% de gains vont être critiques. Une demi-seconde de retard sur la correction de trajectoire d'une sonde spatiale qui voyage à 17km/s peut effectivement poser problème pour peu que ça nécessite autant d'opérations.

Maintenant, dans les faits, n'étant pas un puriste de l'optimisation mais un "utilisateur" du langage, je vais préférer faciliter l'écriture et la relecture pour une maintenance aisée puis laisser le compilateur faire son boulot comme il l'entend. Je ne suis pas en train de dire qu'il faut faire n'importe quoi en se reposant uniquement sur les capacités assez extraordinaires des bécanes actuelles : je ne bosse pas chez Ubisoft :-°. Mais la norme le permet et il ne me semble pas que cette possibilité qui est offerte fasse vraiment débat au sein de la communauté (on est loin de la tempête qu'engendre un goto), l'utilisation de variables globales pour tout et n'importe quoi est déjà un peu plus discutable en terme d'état de l'art.

Pour faire de petits jeux sans prétention (ou pas trop), je me rend compte que pour mon plus gros projet existant, je suis obligé de coller du SDL_Delay() pour l'empêcher de tourner trop vite et que chaque boucle du programme consacre presque 90% du temps à attendre la fin de cette pause. Gagner le milliardième d'une demi-seconde importe peu à ce niveau là.

@robun : Ne le prend surtout pas comme une attaque personnelle, j'ai très bien compris que tu t'étais intéressé uniquement aux écarts qu'une méthode ou une autre pouvait engendrer sans pour autant prendre parti. Je me permet juste de recadrer pour les petits malins qui s'amusent à compter les coups d'horloge pour faire ceci ou cela et pondent du code imbitable sous prétexte qu'un bout d'algo va se faire en 5 coups d'horloges plutôt qu'en 7. Ou pire, un débutant qui va se persuader que son programme sera plus efficace s'il passe tout en variables globales...

Bonne continuation.

-
Edité par drx 19 janvier 2020 à 15:04:29

  • Partager sur Facebook
  • Partager sur Twitter

Bonhomme !! | Jeu de plateforme : Prototype.

19 janvier 2020 à 15:16:12

Je pense que dans les cas où le temps de calcul est critique, gagner 10 % n'est pas énorme, mais c'est l'accumulation de petits gains de 10 % qui peut devenir intéressante.

J'ai fait autrefois des études de maths appliquées, et j'ai retrouvé récemment, dans mes vieux cours, une photocopie d'un document parlant de calcul en Fortran : il expliquait toutes les petites optimisations qu'on pouvait réaliser pour grapiller un peu de temps. Chaque optimisation ne faisait pas gagner grand chose, mais leur accumulation, si.

C'est un peu dans cet esprit que je me suis posé la question.

J'aime bien définir les variables locales dans les blocs où elles sont utilisées, c'est pour moi une question de cohérence et de lisibilité. Et puis je n'aime pas le principe des noms de variables explicites faisant plusieurs mots (sans doute par manque d'habitude et parce que je programme surtout des calculs, je trouve ça illisible) du coup mes variables ont souvent des noms courts, et là il est indispensable qu'elles soient déclarées pile à l'endroit où elles servent. Bref, je ne vais pas changer mes habitudes pour ces 10 %, et je recommanderai toujours de déclarer ses variables pile à l'endroit où elles servent. :)

(Précision : je ne fais pas du C en professionnel, c'est juste pour mes loisirs, donc en effet je me pose des questions mais je n'affirme rien, hein !)

  • Partager sur Facebook
  • Partager sur Twitter
19 janvier 2020 à 15:17:47

Et qu'arrive-t-il si je déclare 3 fois dans le même bout de code:
for(int i=0; ...)
Ça ressemble à de la redondance.
Ceci dit, pour des tests ou des oublis, ça ne me dérange plus de définir localement.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

19 janvier 2020 à 23:01:05

Non la déclaration d'une variable dans une boucle ne va pas demander la "création" de quoi que ce soit au moment de l'exécution de cette boucle. Arrêtez avec cette "création", ça veut rien dire. On déclare ou on définit des variables, et on les utilise. C'est tout.

Il faudrait que vous regardiez le code assembleur généré par le compilateur, ça vous éviterait de fantasmer.

Allez, une fonction qui échange le contenu de deux tableaux. Deux versions :

void echange (int t1[], int t2[], int n) {
  for (int i = 0; i < n; i ++) {
    int tmp = t1[i];
    t1[i] = t2[i];
    t2[i] = tmp;
  }
}

void echange2 (int t1[], int t2[], int n) {
  int i;
  int tmp;
  for (int i = 0; i < n; i ++) {
    tmp = t1[i];
    t1[i] = t2[i];
    t2[i] = tmp;
  }
}

Le code produit par le compilateur (gcc -Os) est EXACTEMENT LE MEME

echange2:
	xorl	%eax, %eax
.L2:
	cmpl	%eax, %edx
	jle	.L5
	movl	(%rdi,%rax,4), %ecx
	movl	(%rsi,%rax,4), %r8d
	movl	%r8d, (%rdi,%rax,4)
	movl	%ecx, (%rsi,%rax,4)
	incq	%rax
	jmp	.L2
.L5:
	ret

Le registre eax sert à faire le compteur de boucle i, et le yoyotage avec le variable tmp est remplacé par l'utilisation de 2 registres, comme si on avait fait

int tmp1 = t1[i];
int tmp2 = t2[i];
t1[i] = tmp2;
t2[i] = tmp1;


parce que c'est mieux pour l'utilisation du cache, me semble-t-il. Le compilateur en fait exactement la même chose.

Conclusion : quand on dit que, quand on rentre dans un bloc, ça alloue des variables, c'est une FICTION. Ca fait comme si, du point de vue du programmeur naïf, mais en fait non. D'une part beaucoup sont éliminées, ou remplacées par des registres,  et en général, si il y a besoin de réserver quelque chose sur la pile pour stocker, c'est généralement fait dans l'entrée dans la fonction.

Donc n'imaginez pas des impacts sur les performances sans y regarder de plus près. Sinon vous tombez dans la superstition.

(les complications avec les VLA variable length arrays viennent en réalité de là, pas du risque de débordement qu'on évoque habituellement. Pour peu qu'on  ait deux  VLA dans la même fonction, bonjour la galère pour y accéder efficacement).



-
Edité par michelbillaud 19 janvier 2020 à 23:08:07

  • Partager sur Facebook
  • Partager sur Twitter