Langage C

Discutez d'informatique ici !
Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 17 Nov 2013, 16:10

Bonjour,

Il se passe exactement la même chose avec ou sans la condition.

Si tu as :
Code: Tout sélectionner
int f(int *a) {
    *a *= 2;
    return *a;
}

int main(void) {
   a = 5; /* a = 5 */
   f(&a); /* a = 10 */
   f(&a); /* a = 20 */
}


Lorsque tu vas écrire if (f(&a) == f(&a)), dans ton premier appel, a = 5, dans le second a = 10.

J'avoue ne pas bien saisir ta seconde question. Est-ce que tu aurais un exemple de ce que tu souhaiterais faire en C ?



Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 17 Nov 2013, 17:29

Oki pour la première merci.


Pour la seconde; comment dire, si je voulais par exemple ne plus écrire int nb; mais entier nb.

nb serait un nombre de type entier qui aurait exactement les même propriétés que int.
Je n'ai pas trouvé la syntaxe permettant de créer un tel type.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 17 Nov 2013, 18:13

peut-être
Code: Tout sélectionner
typedef int entier;

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 17 Nov 2013, 18:17

joel76 a écrit:peut-être
Code: Tout sélectionner
typedef int entier;



Effectivement ça a marché c'était bien ça. Merci !

Maintenant si je veux porter le problème un peu plus loin et que je veux créer disons un type chiffre qui contiendrais 1..9; ça serait un "sous type" de int mais il ne contiendrait pas tout les int.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 17 Nov 2013, 18:26

Je nse suis pas sur, mais le type enum me paraît indiqué.
Code: Tout sélectionner
typedef  enum my_int {zero, un, deux, trois, quatre, cinq, six, sept, huit, neuf};

Zero a la valeur numerique 0.
J' ai testé tu peux peut-être faire le test if (un + deux == trois) au moins avec VS 2010.

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 17 Nov 2013, 18:46

Ok; ça fait un peu bizarre mais pourquoi pas; je testerais à l'occasion si j'ai besoin de quelque chose comme ça.

Autre question; est ce que j'ai la bonne syntaxe pour réaliser une structure de donnée:

Code: Tout sélectionner
struct {ELEMENT tableau[TMAX];
           ELEMENT tete;}pile;
/*ELEMENT ayant été définit comme le nouveau type d'int*/


Avec ceci je crée une structure répondant au nom de pile et étant composé d'un tableau de constante TMAX éléments et de l'élément tete qui servira de compteur ?


Si je veux manipuler cette structure et par exemple initialiser les valeurs y a t'il une syntaxe particulière ? En ada j'aurais fait quelque chose du style pile.tableau[tete]=0 pour tete de 0 à 49.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 17 Nov 2013, 19:14

Bonjour,

Code: Tout sélectionner
struct {
    Element tableau[TMAX];
    Element tete;
}Pile;


Tu as plusieurs solutions pour initialiser cela : en passant par un pointeur ou non.

Solution 1 :
Code: Tout sélectionner
struct Pile *ma_struct = NULL;

ma_struct = calloc(1, sizeof(struct pile));
if (ma_struct == NULL) {
    fprintf(stderr,  "calloc : %s\n", strerror(errno)); /* Fonction envoyant l'erreur sur stderr inclure #include
    return EXIT_FAILURE;
}

/* Utilisation */
ma_struct->tableau[0];
ma_struct->tete = 3;


Seconde solution :

Code: Tout sélectionner
struct Pile ma_structure;
memset(&ma_structure, 0, sizeof(struct pile)); /* Inclure stdlib.h, fonction mettant la mémoire à 0 pour la taille de struct pile */

/* Utilisation */
ma_struct.tableau[0];
ma_struct.tete = 3;

/* On oublie pas le free */
free(ma_struct);
ma_struct = NULL;



Si tu veux te passer du mot clef struct dans ta déclaration, tu peux définir ta structure comme ceci.

Code: Tout sélectionner
typedef struct {
   Element tableau[TMAX];
   Element tete;
} Pile;

/* A la place de "struct pile ma_struct" */
Pile ma_struct;
Pile *mon_ptr_struct = NULL;

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 17 Nov 2013, 22:28

Bonsoir; malheureusement lorsque l'on commence à me parler de memset, calloc ou autre mystification que je n'ai pas encore vu; je suis totalement perdu ;)


Voici ce que j'ai fais
Code: Tout sélectionner
typedef int ELEMENT;

struct Pile{
    ELEMENT tableau[TMAX];
           ELEMENT tete;
           };

void initPile(struct Pile Pile1);

int main()
{
struct Pile Pile1;
    initPile(Pile1);

return 0
}

void initPile(struct Pile Pile1)
{
    int k;
    for (k=0;k<TMAX;k++)
    {
        Pile1.tableau[k]=0;
    }
}



Si je passe un test des valeurs dans la fonction void initPile; les valeurs se passent bien.

Si je veux les retrouver en sortie de ma fonction dans le main; je dois donc passer par des pointeurs; hors je sais pas si c'est à cause de la structure; mais je n'arrive pas à le passer comme il faut j'obtiens toujours des erreurs à la compilations.


Que dois je modifier à ce code pour retrouver les valeurs du tableau à 0 dans mon main ?
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 17 Nov 2013, 22:39

Pour les erreurs, il te manque un #include et un ";" après le return 0. Il te manque également un #define TMAX 10

Il faut que tu envoies un pointeur dans ta fonction.

Lorsque tu passes une variable en paramètre, une copie de cette variable est faite et est détruite à la fin de la fonction. C'est pour cette raison que ton programme ne marche pas.

Tu dois ecrire la fonction
Code: Tout sélectionner
void initPile(struct Pile *Pile1)
et donc dans cette fonction utilisée
Code: Tout sélectionner
Pile1->tableau[i]
équivalent à
Code: Tout sélectionner
(*Pile1).tableau[i]


Tu devras donc lors de ton appel de fonction utiliser
Code: Tout sélectionner
initPile(&Pile1)

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 17 Nov 2013, 22:46

Pour les erreurs, il te manque un #include et un ";" après le return 0. Il te manque également un #define TMAX 10


Je les avais bien; je les ai simplement omis en mettant sur le fofo désolé :mur:


Lorsque tu passes une variable en paramètre, une copie de cette variable est faite et est détruite à la fin de la fonction. C'est pour cette raison que ton programme ne marche pas.


Je suis d'accord; d'où l'utilité du pointeur, je suis bien d'accord.


Tu dois ecrire la fonction
Code:
void initPile(struct Pile *Pile1)


Ok; mon soucis venait du fait que je tentais d'écrire struct * Pile Pile1 à priori; je m'en vais tout de suite tester ta syntaxe; merci encore.


EDIT: Sa a marché nikel; mais le genre de chose entouré *Pile1 avec des parenthèses j'aurais pas pu le deviner.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 17 Nov 2013, 23:02

En fait si tu aurais pu.

Reprenons ta fonction f(x) :

Code: Tout sélectionner
void f(int *x) {
    *x = *x * 2;
}


Tu es obligé d'utiliser *x pour obtenir la valeur du pointeur *

C'est le même principe pour la structure
Code: Tout sélectionner
*Pile1.tableau[i]


*Pile1 accède au valeur de la structure et .tableau[i] à la valeur du i-ème élément du tableau.

On note plus couramment Pile1->tableau[i] mais cette écriture *Pile1->tableau[i] peut se retrouver assez souvent puisque les deux écritures sont équivalentes.

Dlzlogic
Membre Transcendant
Messages: 5273
Enregistré le: 14 Avr 2009, 12:39

par Dlzlogic » 17 Nov 2013, 23:16

Bonsoir Rockleader,
Je sus en admiration devant votre persévérance à chercher des détails de syntaxes, des cas particuliers ou je ne ne sais quoi concernant le langage C.
Comme tout langage et en particulier informatique, il ne résule d'aucune logique particulière ou intuition quelconque, c'est un langage et ça s'apprend.
Dans ce domaine, il me semble qu'on n'a pas trouvé mieux qu'un cours, sur un bouquin ou sur le net.
Il est tout à fait justifiable de poser des questions, mais pas sur des choses qui font partie du langage lui-même, c'est à dire sur des choses qui doivent être connues et comprises avant de poser la question.
Le problème majeur et qui est est tout à fait pénalisant pour voue est que dans le cadre d'un forum, on répond de façon précise à une question plus ou moins précise.
Vous posez une question, avec une idée derrière la tête, on répond comme on peut et ça devient pour vous, parole de vérité, alors que le vérité est probablement, pas forcément plus compliquée, mais souvent exprimée autrement.
Il y a des gens qui ont élaboré des cours avec une progression étudiée, soignée et murement réfléchie, ce n'est pas pour rien.
Ampholyte vous a montré 3 façon d'utiliser une structure. Vous avez décidé qu'une méthode faisait appel à des choses que vous n'aviez pas apprises. Cela me parait un peu énorme. Qu'attendez-vous donc pour aller voir ce dont il s'agit ?

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 25 Nov 2013, 15:15

Bonjour; bonsoir,

dans le cadre d'une nouvelle série de tp; je me suis penché sérieusement sur tous les paramètres de correspondances de la table ascii en ce qui concerne les controles de chaines. \n \0 etc.


Je viens de voir la puissance que pouvait apporter notamment la fonction fgets que je trouve très intéressant. Seulement elle a un gros défaut à mon sens en insérant un retour à la ligne \n donc en fin de saisie.

J'ai donc pensé créer ma propre fonction qui corrigerait ce problème en partant de la fonction fgets et en modifiant le \n par un \0.

Est ce la bonne méthode à adopter ?

Egalement, j'aimerais pouvoir me servir de la fonction lorsque je le désire un peu comme je le fais avec des fonctions de bibliothèques .h

N'ayant pas encore eu l'opportunité de me pencher sur la créations de fichiers header; j'aurais aimé savoir de manière générale ce qu'il faut mettre dans le fichier header. L'en tête de la fonction ? Puis ensuite il suffit de rajouter dans le .c du main un include nom_header.h ?

Merci à vous.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Dlzlogic
Membre Transcendant
Messages: 5273
Enregistré le: 14 Avr 2009, 12:39

par Dlzlogic » 25 Nov 2013, 16:40

Bonjour,
D'après mon bouquin, la fonction fgets conserve '\n' mais n'en rajoute pas.
Le nombre de fonctions de base que j'ai cru bon de surcharger est très, très limité.
Dans ce cas présent de lecture, j'ai effectivement fait une fonction que j'ai appelé Carte, mais c'est plus pour des raisons historiques. Cette fonction contient un fgets.
Donc la présence de '\n' ne me parait pas être une raison suffisante pour la surcharger.

Pour le fichier header, on met les déclarations utilisées par plusieurs modules c ou cpp. On peut y trouver des déclarations de structure, de typedef, et surtout des prototypes de fonctions.
Voila un exemple (très simple) de header
Code: Tout sélectionner
#ifndef UcreArbreH
#define UcreArbreH
#include

#include
#include
#include
struct NOEUD
{
  int rang;
  TList *Fils;
};
int CreArbre(FILE *ecr);
bool ChercheFils(NOEUD *Dep, NOEUD *Pere, NOEUD *Fin);
//---------------------------------------------------------------------------
#endif
Un point très important est que les deux premières lignes soient "#ifdef ... et #define ..." et la dernière "#endif".
Ca sert à ne pas répéter des déclarations. Si on l'oublie, ça plante, mais la faute est difficile à trouver.

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 25 Nov 2013, 16:59

Bonjour,

Pour compléter un peu les propos de Dlzlogic, la fonction fgets ne rajoute pas de \n. Elle lit une ligne et stocker une ligne entière (\n compris) dans une chaine (si la chaine est suffisemment grande).

Pour retirer le \n, cela n'est vraiment pas très compliqué.

Voici un exemple de ce que tu souhaites faire.

main.c
Code: Tout sélectionner
#include "fonction.h"
int main(void) {
    int a = 0;
    int b = 0;
    int res = 0;
    res = ma_fonction(a, b);

    fprintf(stdout, "%d\n", res);

    return EXIT_SUCCESS;
}


fonction.h
Code: Tout sélectionner
#ifndef DEF_FONCTION_H
#define DEF_FONCTION_H
#include
#include

int ma_fonction(int a, int b);
#endif


fonction.c
Code: Tout sélectionner
#include "fonction.h"
int ma_fonction(int a, int b) {
    return a*b;
}

joel76
Membre Relatif
Messages: 230
Enregistré le: 11 Fév 2013, 15:31

par joel76 » 25 Nov 2013, 18:40

Pour préciser le propos de ampholyte, il est très important que le \n soit dans le buffer de saisie de fgets, car sa présence signale que la ligne complète a été saisie, s'il est absent il reste des caractères à lire et il faut continuer la lecture par fgets jusqu'à la présence de cet '\n'.

Avatar de l’utilisateur
Rockleader
Habitué(e)
Messages: 2126
Enregistré le: 11 Oct 2011, 18:42

par Rockleader » 25 Nov 2013, 18:51

Merci; effectivement ça marche bien comme ça; j'ai testé avec une fonction toute bête d'addition.

Pour répondre à Dzlogic; en soit il n'y a pas d’inconvénient majeur, mais il y a quelques cas gênant.

Imaginons quelque chose de ce style

fgets(prénom,20,stdin); ==> TU entres Toto à l'exe
printf("Vous vous appelez %s !",nom); ==> A l'exe tu auras écris : Vous vous appelez Toto et ton point interrogation se prend le retour à la ligne...c'est pas super non plus...d'où ce que je disais d'en faire une autre à partir de fgets...mais bon je suis d'accord là c'est être tatillon et il y a des choses bien plus importantes.





Après mon tp de cet aprèm; j'aurais eu un code à vous montrer; mais pour je ne sais quelle raisons lorsque je copie sur ma clef mes document sont vide une fois de retour sur mon pc portable...du coup j'ai plus le code.


Je vais tout de même vous expliquer ce que cela faisait.


Je rentrais une chaîne de caractère avec un fgets que je faisais volontairement commencer par des espaces et/ou tabulations.

J'ai alors écris une fonctions qui prenait en paramètres la chaîne et qui supprimait les espaces. Ou plutôt devrais je dire qui créait une seconde chaîne à partir du premier caractère différent de \t ou espace.

La fonction elle même marchait correctement un printf à l'intérieur le prouvait.

En revanche; lorsque je récupérais la chaine donné en retour de la fonction et que je faisais un printf de cette chaîne; j'obtenais en sortie un résultat complètement différent avec des caractères divers et variés.

Voulant trouver d'ou venait le problème; j'ai fait un printf à la fin de ma fonction pour voir si j'avais la bonne valeur pur ma chaîne. La valeur s'affichait bien et la valeur en sortie dans le main également...

Donc en gros; sans printf en sortie de ma fonction je n'obtenais pas le bon résultat dans le main; mais avec un printf dans la fonction; j'obtenais non seulement le résultat dans la fonction mais aussi dans le main.
Et là je vous avoue avoir passé tout mon tp là dessus sans comprendre ce qu'il se passait au niveau du compilateur.

On m'a dit que c'était peut être une histoire de buffer; du coup j'ai fait ma fonction autrement; mais j'aurais vraiment voulu savoir ce qui provoquait ce problème.

Au besoin je pourrais tenter de reconstituer le code.

Merci à vous.
Cette histoire est entièrement vraie puisque je l'ai inventé du début à la fin !

Dlzlogic
Membre Transcendant
Messages: 5273
Enregistré le: 14 Avr 2009, 12:39

par Dlzlogic » 25 Nov 2013, 19:12

Concernant le fgets, je crois que je n'ai jamais fait de saisie avec stdin, j'ai toujours travaillé avec des fichiers, donc, je vois pas trop d'où peut venir ce point d'interrogation.
Concernant la chaine lue, elle doit aller dans un buffer. Celui-ci doit exister avec une longueur suffisante. Sinon, on ne sait pas du tout ce qui se passe.
Il y a un point à signaler qui me parait important : sous Unix et linux, le caractère fin de ligne est le caractère '0x0D', alors que sous Windows, c'est '0x0D'+'0x0A'.
Cela fait que si on affiche un texte provenant de Linux avec Windows, il n'y a pas de CRFL détecté et toutes les lignes sont accolées, sur une seule ligne.
Ce genre de détail fait partie des joies de l'informatique.

Avatar de l’utilisateur
ampholyte
Membre Transcendant
Messages: 3940
Enregistré le: 21 Juil 2012, 07:03

par ampholyte » 25 Nov 2013, 19:22

Rockleader a écrit:Merci; effectivement ça marche bien comme ça; j'ai testé avec une fonction toute bête d'addition.

Pour répondre à Dzlogic; en soit il n'y a pas d’inconvénient majeur, mais il y a quelques cas gênant.

Imaginons quelque chose de ce style

fgets(prénom,20,stdin); ==> TU entres Toto à l'exe
printf("Vous vous appelez %s !",nom); ==> A l'exe tu auras écris : Vous vous appelez Toto et ton point interrogation se prend le retour à la ligne...c'est pas super non plus...d'où ce que je disais d'en faire une autre à partir de fgets...mais bon je suis d'accord là c'est être tatillon et il y a des choses bien plus importantes.


Il est très courant de faire un petit traitement à la fin du fgets pour remplacer le '\n' par un '\0'


Je rentrais une chaîne de caractère avec un fgets que je faisais volontairement commencer par des espaces et/ou tabulations.

J'ai alors écris une fonctions qui prenait en paramètres la chaîne et qui supprimait les espaces. Ou plutôt devrais je dire qui créait une seconde chaîne à partir du premier caractère différent de \t ou espace.

La fonction elle même marchait correctement un printf à l'intérieur le prouvait.

En revanche; lorsque je récupérais la chaine donné en retour de la fonction et que je faisais un printf de cette chaîne; j'obtenais en sortie un résultat complètement différent avec des caractères divers et variés.

Voulant trouver d'ou venait le problème; j'ai fait un printf à la fin de ma fonction pour voir si j'avais la bonne valeur pur ma chaîne. La valeur s'affichait bien et la valeur en sortie dans le main également...

Donc en gros; sans printf en sortie de ma fonction je n'obtenais pas le bon résultat dans le main; mais avec un printf dans la fonction; j'obtenais non seulement le résultat dans la fonction mais aussi dans le main.
Et là je vous avoue avoir passé tout mon tp là dessus sans comprendre ce qu'il se passait au niveau du compilateur.

On m'a dit que c'était peut être une histoire de buffer; du coup j'ai fait ma fonction autrement; mais j'aurais vraiment voulu savoir ce qui provoquait ce problème.

Au besoin je pourrais tenter de reconstituer le code.

Merci à vous.


Sans ton code c'est difficile de t'aider. Ton problème peut provenir de plusieurs points :
* Un dépassement de buffer (tu écris en dehors de la zone allouée)
* Le renvoi d'un pointeur au dehors de la zone allouée
* Tu ne renvoies pas un char * à la fin de ta fonction

@Dlzlogic : le point d'exclamation provient d'ici ^^
Code: Tout sélectionner
printf("Vous vous appelez %s !",nom);
comme le '\n' dans le nom est toujours présent le '!' sera affiché à la ligne

PS : Petite fonction pour remplacer le '\n' :

Code: Tout sélectionner
char *ptr = NULL;

ptr = strchr(ma_chaine, '\n');
if (ptr != NULL) {
    *ptr = '\0';
}

Dlzlogic
Membre Transcendant
Messages: 5273
Enregistré le: 14 Avr 2009, 12:39

par Dlzlogic » 25 Nov 2013, 19:34

Bon, oui, point d'exclamation et pas d'interrogation.
Vu que c'est un nom il est assez normal de le retirer de la chaine.

 

Retourner vers ϟ Informatique

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 4 invités

Tu pars déja ?



Fais toi aider gratuitement sur Maths-forum !

Créé un compte en 1 minute et pose ta question dans le forum ;-)
Inscription gratuite

Identification

Pas encore inscrit ?

Ou identifiez-vous :

Inscription gratuite