Oui, mais on commence par caster un simple void*, et on finit par caster le retour de malloc()...
(ce qui, si on n'a pas inclut stdlib.h, peut cacher l'erreur, menant à la catastrophe sous Win64 ou sur des systèmes basés sur processeur 68k...)
Oui, mais on commence par caster un simple void*, et on finit par caster le retour de malloc()...
(ce qui, si on n'a pas inclut stdlib.h, peut cacher l'erreur, menant à la catastrophe sous Win64 ou sur des systèmes basés sur processeur 68k...)
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Combien va-t-il falloir répéter qu'on ne peut pas déréférencer un pointeur de type void, tout simplement parce que le compilateur n'a pas d'information sur la taille de l'objet pointé et ne peut donc pas mettre en oeuvre l'arithmétique des pointeurs. Tout cela est expliqué dans le moindre livre de C.
Pas de Wi-Fi à la maison : CPL
Pas de Wi-Fi à la maison : CPL
Certes, mais l'erreur est de dire "il faut donc faire un cast". C'est pas 'il faut" mais "on peut". Mais ce n'est pas le point le plus important. Ce qui compte, c'est qu'il faut[1] un pointeur local du type 'utilisateur'.
-------------------
[1] Certes, on peut s'en passer, mais au prix d'un extrême complication du code qui le rend illisible et inmaintenable...
Pas de Wi-Fi à la maison : CPL
Je crois comprendre!
C'est que &gpln[0] est un comprtement indéfini, alors que gpln ne sous-entend pas de comportement indéfini, puisque c'est l'addresse emmagasinée dans le pointeur void!
Cependant, en lisant vos derniers post, je m'interroge sur cela :
Thierry aurait t-il pu remplacer cette ligne par :
Code : Sélectionner tout - Visualiser dans une fenêtre à part int character = *((unsigned char *) c);
int *character = c;
Et utiliser *character pour le déréférencer?
Voilà...
Merci,
Array
Non, c'est équivalent à:
Thierry
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 void print_char(void *c) { if (c != NULL) { /* -tc- affectation de l'adresse du caractere a afficher a un pointeur local du type qui va bien */ unsigned char *pc = c; /* -tc- dereferencement de ce pointeur pour recuperer la valeur du caractere a afficher */ int character = *pc; /* -tc- affichage */ printf("%c ", character); } }
"The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
"If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow
FAQ-Python FAQ-C FAQ-C++
+
Bonjour,
J'aurais deux questions...
1)Comme vous le savez, le type "double" prend plusieurs case de mémoire pour une seule variable.
Je voulais savoir si, à l'aide de pointeurs, il serait possible d'accéder individuellement les cases qui forment le "double".
2)J'aimerais savoir pourquoi la calculatrice Windows ne fait pas d'erreurs lorsqu'elle traite des nombres à virgule...
Merci,
Array
Pour la première question tu peux éventuellement t'aider d'une union comme celle-ci :
Ensuite, tu peux accéder aux valeurs comme ça :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 union DoubleChar { double d; char c[sizeof(double)]; } DoubleChar;
Sinon, la calculatrice Windows peut utiliser des flottants avec une plus grande précision, ou alors elle utilise des types à elles.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 DoubleChar var; var.d = 5.5; var.c[2] // accès au troisième octet du double.
"The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
"If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow
FAQ-Python FAQ-C FAQ-C++
+
C'est un comportement indéfini. Tu ne peux pas retirer d'une union autre chose que ce que tu as mis dedans. Ainsi, dans le cas du code ci-dessus, tu ne peux initialiser var via le champ d de l'union et accéder à sa valeur via le c. La seule exception à cette règle, c'est lorsque tu as une union de structures ayant une séquence initiale commune.
Thierry
"The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
"If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow
FAQ-Python FAQ-C FAQ-C++
+
Par case mémoire, je suppose que tu parles de 'byte'...
Oui, avec un 'hack' horrible comme ça :Je voulais savoir si, à l'aide de pointeurs, il serait possible d'accéder individuellement les cases qui forment le "double".
je ne vois pas bien à quoi ça peut servir...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 double d = 12.34; unsigned char *p = (unsigned char *)&d;
Tu peux le prouver ?2)J'aimerais savoir pourquoi la calculatrice Windows ne fait pas d'erreurs lorsqu'elle traite des nombres à virgule...
Pas de Wi-Fi à la maison : CPL
Eh, j'y tâcherai.Envoyé par Emmanuel Delahaye
Mais je n'ai pas le temps là maintenant.
J'en suis presque sûr...
Merci pour vos réponses.
---
Toutefois, quelque chose me tracasse à nouveau.
Voici un code:
Voici des erreurs :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 #include <stdio.h> #include <stdlib.h> void fonction(const int atest[][1]) { putchar('\0'); return; } int main(void) { int atest[2][1]; atest[0][1] = 192; atest[1][1] = 324; fonction(atest); return 0; }
Code icc : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 Intel(R) C++ Compiler for applications running on IA-32, Version 10.0 Build 20070613 Package ID: W_CC_C_10.0.026 Copyright (C) 1985-2007 Intel Corporation. All rights reserved. cplc.c cplc.c(13): warning #167: argument of type "int (*)[1]" is incompatible with parameter of type "const int (*)[1]" fonction(atest); ^ ipo: remark #11001: performing single-file optimizations ipo: remark #11005: generating object file C:\DOCUME~1\YANNIC~1\LOCALS~1\Temp\ipo_148.obj Microsoft (R) Incremental Linker Version 6.00.8168 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. -out:cplc.exe -nodefaultlib:libguide_stats.lib -nodefaultlib:libguide40_stats.lib -defaultlib:libguide.lib C:\DOCUME~1\YANNIC~1\LOCALS~1\Temp\ipo_148.obj
J'ai essayé différents casts... mais... déception.
Comment faire pour ne plus avoir cette erreur, le plus possible avec un cast.
Merci,
Sincèrement,
Array
Pas de Wi-Fi à la maison : CPL
lol.
Eh oui, je l'admets, cela peut enegndrer de la confusion, mais ce compilateur est bien un compilateur de C. En fait, on a tendance à appeller ICC "Intel C/C++ Compiler", mais le vrai nom officiel du compilateur est Intel C++ Compiler. Donc... ce compilateur est valable pour les deux.
Me crois tu assez ignorant pour faire une telle bévue?
Je sais différencer le C du C++!
D'autre part, en faisant des recherches, j'ai trouvé la cast qu'il me fallait.
Ce que je me demande, c'est cela : Si j'avais eu un tableau à trois dimensions, aurais-je pu faire "const int (*)[SIZE][SIZE2]"???
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 #include <stdio.h> #include <stdlib.h> void fonction(const int atest[][1]) { putchar('\0'); return; } int main(void) { int atest[2][1]; atest[0][1] = 192; atest[1][1] = 324; fonction((const int (*)[1]) atest); return 0; }
De même, selon Emmanuel :
Ainsi, ce n'est que la première taille qui peu ne pas être spécifiée.Pour définir un paramètre de type pointeur sur un tableau à 2 dimensions, on serait tenté d'écrire type p[][], ce qui serait une erreur de syntaxe. En effet, la notation [] est une notation abrégée de [TAILLE] dans les cas où cette taille est ignorée par le compilateur, c'est à dire lorsque la dimension concernée est la plus à gauche. Les syntaxes suivantes sont légales :
type_retour fonction (int p[])
type_retour fonction (int p[12])
type_retour fonction (int p[][34])
type_retour fonction (int p[56][78])
etc.
Voilà,
Merci,
Array
Pas besoin de cast. Il suffit de mettre le bon type. Si tu tiens au 'const', il doit s'appliquer aux données du tableau, on est donc obligé d'utiliser la notation 'pointeur de tableau'. Et attention aux débordements de tableau... :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 #include <stdio.h> #include <stdlib.h> void fonction (int (*const atest)[1], size_t lin, size_t col) { size_t i; for (i = 0; i < lin; i++) { size_t j; for (j = 0; j < col; j++) { printf ("%4d", atest[i][j]); } printf ("\n"); } return; } int main (void) { int atest[2][1]; atest[0][0] = 192; atest[1][0] = 324; fonction (atest, sizeof atest / sizeof *atest, sizeof *atest / sizeof **atest); return 0; }
Pas de Wi-Fi à la maison : CPL
Merci pour cette réponse.
J'aime bien mieux utiliser la notation 'pointeur de tableau' que de faire de longs cast comme je faisais.
Voilà que m'interroge maintenant au sujet de...
...les structures.
Je me suis documenté sur les structures.
Mais j'ai de la difficulté à saisir le principe.
Alors, voilà la question :
À quoi servent les structures?
Pourquoi les utilsent-on?
Comment les utiliser?
Quel est l'intérêt d'utiliser une structure?
Si vous pouviez me prêter secours...
Merci,
Array
Il y a 3 questions qu'on peut regrouper en une.
Une structure permet de regrouper plusieurs variables des liens entre elles dans une seul et des les déplacer/utiliser/modifier en une seule variable.
Par exemple, pour un carnet d'adresse on va faire une structure "Personne" qui va contenir une chaîne de caractère pour le nom, une pour le prénom, une pour l'adresse, le numéro de rue, le code postale, la ville et le numéro de téléphone.
Ce qu'on manipulera ce sont des Personne et pas 5 variables différentes.
Donc on définit une structure comme ça :
Pour créer une variable de ce type de structure, on va simplement écrire :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 struct nomStruct { type_champ1 nom_champ1; type_champ2 nom_champ2; ... }; // ne pas oublier le ; à la fin
Et comme "struct nomStruct" et lourd à écrire, on va créer un type avec le mot clé typedef :
Code : Sélectionner tout - Visualiser dans une fenêtre à part struct nomStruct maVar;
Et là on pourra simplement écrire :
Code : Sélectionner tout - Visualiser dans une fenêtre à part typedef struct nomStruct nomType;
maVar sera de type nomType qui correspond au type struct nomStruct.
Code : Sélectionner tout - Visualiser dans une fenêtre à part nomType maVar;
Ensuite, pour accéder aux champs, on utilise l'opérateur ".", exemple :
Si, maintenant tu fais un pointeur sur ton type, tu peux utiliser l'opérateur "->", par exemple :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 // autre façon d'écrire le typedef avec une struct typedef struct Rationnel { int numerateur; unsigned denominateur; } Rationnel; // ... Rationnel nombre; nombre.numerateur = 5;
Après tu peux utiliser tes structures dans des types de retour de fonctions ou dans des paramètres de fonctions.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 Rationnel nombre; Rationnel *ptr = &nombre; ptr->numerateur = 5; // équivaut à : (*ptr).numerateur = 5;
J'en déduis donc que c'est plus pratique qu'essentiel?
Sinon, donnez moi un exemple où un struct est essentiel au fonctionnement du programme... s.v.p.
De plus...
Dans l'exemple de psychoH13, est-ce nombre qui aura la valeur de 5 ou nombre est-il moyen d'accéder à numerateur? Autrement dit, qu'est-ce qui prendra la valeur de 5 ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2nombre.numerateur = 5;
Ce que j'aimerais également savoir, c'est :
- Pourquoi je ne peux pas faire de "size_t i = 273;" dans une fonction?!
- Peut-on modifier une valeur d'une structure en permanence, où une structure n'est-elle qu'une déclaration?
En tout cas ça m'a l'air utile!
EDIT :
Dans un snippet de code comme celui-ci
Serait-il mieux d'utiliser une structure?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 while (lntype < 4) { switch (lntype) { case DESCENDING: fdim_i = 0; sdim_i = 0; fdim_i_addv = 1; sdim_i_addv = 1; taskind = DESCENDING; fdim_ind = dim_sz-1; break; case ASCENDING: fdim_i = dim_sz-1; sdim_i = 0; fdim_i_addv = -1; sdim_i_addv = 1; taskind = ASCENDING; fdim_ind = 0; break; case VERTICAL: fdim_i = dim_sz-1; sdim_i = 0; fdim_i_addv = 0; sdim_i_addv = 1; taskind = VERTICAL; sdim_ind = dim_sz-1; break; case HORIZONTAL: fdim_i = 0; sdim_i = 0; fdim_i_addv = 1; sdim_i_addv = 0; taskind = HORIZONTAL; fdim_ind = dim_sz-1; break; }
Que d'interrogations!
Tu peux toujours te passer des structures, les structures te permettent de pouvoir utiliser plusieurs variables différentes comme si c'était qu'un seul bloc.
Par exemple, si tu écris mes nombres rationnels sans structure ça te donnera :
La seule relation entre les deux variables c'est le début du nom, c'est pas suffisant, toi tu vois la relation, mais pas le compilateur... Si tu veux faire un tableau de nombres rationnels, tu es soit obligé de doubler la taille du tableau et de stocker alternativement un numérateur puis un dénominateur, ou alors de faire 2 tableaux séparés et faire correspondre les indices...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 int nbnum; unsigned nbden;
Je peux te dire, un informaticien se fait pas chier autant, il cherche toujours à simplifier au maximum, les structures sont là pour ça, tu peux faire un tableau de Rationnel de la même manière qu'un tableau d'entier :
.
Code : Sélectionner tout - Visualiser dans une fenêtre à part Rationnel tab[10]; // tableau de 10 Rationnels
Imagine par exemple tu veux faire la multiplication de deux rationnels, voilà le prototype de ta fonction sans structure :
En plus, comme tu peux pas retourner deux valeurs à la fois... Bah tu dois utiliser des pointeurs pour les valeurs de retour. Et une fonction à 6 arguments qui ne fait que la multiplication de deux nombres rationnels... C'est chiant, alors avec une structure voilà ce que ça donne :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 void multiplicationRationnels(int num1, unsigned den1, int num2, unsigned den2, int *resNum1, unsigned *resNum2);
C'est déjà beaucoup plus propre, tu vois clairement que tu multiplies 2 entités distinctes, alors qu'avec le premier t'avais 6 paramètres pour seulement 3 entités distinctes. Et la structure te permet en plus de retourner les deux valeurs en un seul bloc. Donc, c'est pas forcément indispensable, mais du point de vue de la clarté et de la facilité d'écriture, ça l'est.
Code : Sélectionner tout - Visualiser dans une fenêtre à part Rationnel multiplicationRationnels(Rationnel nombre1, Rationnel nombre2);
"nombre" c'est une variable agglomérée, ça signifie qu'elle contient plusieurs variables, en mémoire et sur un processeur 32 bits, ta variable "nombre" prendra 64 bits. En binaire (je ne vais écrire que 8 bits) ça donne ça :
nombre {5/3}: [0000 0101|0000 0011], mais bon tu n'as pas cette séparation nette, ça donne en fait 0000 0101 0000 0011, l'opérateur . va permettre d'accéder à l'une des deux sous-variables :
nombre.numerateur: 0000 0101 et
nombre.denominateur: 0000 0011.
Donc, "nombre" sera un agglomérat des valeurs 5 et 3 qui sont considérées dans le programme comme un seul bloc, mais pour pouvoir accéder à ces valeurs séparément afin de connaître la valeur ou de la modifier, on utilise les noms des champs de la structure.
Pourquoi ne pourrait-on pas le faire ?
On peut modifier les valeurs des champs d'une variable de type structure à n'importe quel moment. La déclaration d'une structure et figée, tu ne peux pas la modifier pendant l'exécution du programme.
En revanche, tu peux définir des variables qui ont pour type la structure en question, par exemple "nombre" est une variables de type "Rationnel" qui est une structure, donc tu peux accéder à chacun de ses champs et en modifier la valeurs.
C'est-à-dire qu'ici fdim_i, sdim_i, fdim_i_addv, sdim_i_addv, taskind et fdim_ind semblent être des variables qui sont utilisées en groupe, tu peux effectivement les mettre dans une structure, ça te permettra de voir que ce sont des variables qui définissent un même objet, cependant ça ne réduira pas le nombre de ligne dans ce switch.
Merci Psycho.
Toutefois, pourquoi je ne peux, dans une structure, faire cela :
Pourquoi mon compilateur me retourne une erreur?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 [...] struct hello { int i = 273; int j; char k; }; [...]
Ensuite, les deux suls opérateurs pour exploiter les structures sont-ils uniquement "." et "->" ?
Les champs de la structure, est-ce les variables déclarées à l'intérieur?
Merci!
Array
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager