Un char[n] est différent d'un char* ???

Résolu
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 - 13 août 2010 à 16:51
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 - 16 août 2010 à 09:37
Bonjour,

J'ai une erreur TRÈS étrange que vraiment je ne comprend pas

Dans "l'application" :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void Toto(char** stValeur)
{
strcpy(*stValeur,"toto");
}

int main(int argc, char* argv[])
{
char* test1;
char test2[10];
test1= (char*)malloc(sizeof(char)*10);
Toto(&test1);
printf("%s\n",test1);
free(test1);
EcrieToto((char**)&test2);
printf("%s\n",test2);
return 0;
}


Qui ne fait rien de compliqué (sa on sera tous d'accord je pense)
Bà sa marche pas
Je reçois une erreur :
Unhandled exception at 0x1026f689 (msvcr90d.dll) in test.exe: 0xC0000005: Access violation writing location 0xcccccccc.

Au moment de l'exécution de la ligne < strcpy(*stValeur,"toto"); > sur test2.
Pourquoi SVP ???
Un tableau de char est bien équivalent à un char* (non, alors on m'aurais mentie )

Je me suis donc dit que j'allais remplacer la ligne <Toto((char**)&test2);> par <Toto(&((char*)test2));>. Bà sa marche pas non plus. Sa compile même plus
e:\test\test.cpp(22) : error C2102: '&' requires l-value


J'ai fait ce test sur Visual studio 6 et 2008 avec les mêmes problèmes.

PS :
Sa par contre sa marche :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void EcrieToto(char** stValeur);
void EcrieToto(char** stValeur)
{
strcpy(*stValeur,"toto");
}

int main(int argc, char* argv[])
{
char* test1;
char test2[10];
test1 =(char*)malloc(sizeof(char)*10);
EcrieToto(&test1);
printf("%s\n",test1);
free(test1);
test1 = test2;
EcrieToto(&test1);
printf("%s\n",test2);
return 0;
}


Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo

12 réponses

cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
13 août 2010 à 18:32
En C, lorsque tu as un tableau comme par exemple: char tab[10]; sa réutilisation est sujette à ambigüité.
L'esperluette est facultative devant ce genre de construction.

Exemple explicatif:
#include <stdio.h>

int main(void)
{
  char test2[10] = {0};

  scanf("%s", test2);
  printf("%s\n", test2);

  scanf("%s", &test2); // Provoque tout de même un petit warning
  printf("%s\n", test2);

  return 0;
}


Lorsque tu fais dans ton code (celui qui ne fonctionne pas): EcrieToto((char**)&test2); il comprend: EcrieToto((char**)test2);. Fais le test, tu verras, tu auras le même comportement.
Forcément, le compilateur produit ensuite un code qui veut traiter un char[] en char**.

Si tu le passe d'abord d'un char*, il s'en sort correctement. D'où ton dernier exemple.


L'explication à ce phénomène étrange est donné dans mon 2ème lien (http://www.coders2020.com/what-is-the-difference-between-char-a-and-char-a) qui n'est pas si hors-sujet que cela.
Un pointeur est stocké à un endroit différent, ce qui n'est pas le cas du tableau.

Démonstration:
#include <stdio.h>

int main(void)
{
  char* a = NULL;
  char b[1] = {42};

  a = malloc(sizeof(char) * 1);

  printf("a: %p %p %p\n", a, &a, &a[0]);
  printf("b: %p %p %p\n", b, &b, &b[0]);

  free(a);

  return 0;
}


Chez moi:

a: 0x2104010 0x7fff0cbcfa08 0x2104010
b: 0x7fff0cbcfa07 0x7fff0cbcfa07 0x7fff0cbcfa07


Donc:
- Dans le cas d'un pointeur: tab != &tab
- Dans le cas d'un tableau: tab == &tab

________________________________________________________________________
Historique de mes créations, et quelques articles:[ http://0217021.free.fr/portfolio
http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
3
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
13 août 2010 à 16:57
Sa par contre sa marche pas :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void EcrieToto(char** stValeur);
void EcrieToto(char** stValeur)
{
char* test;
test = *stValeur;
strcpy(test,"toto");
}

int main(int argc, char* argv[])
{
char* test1;
char test2[10];
test1=(char*)malloc(sizeof(char)*10);
EcrieToto(&test1);
printf("%s\n",test1);
free(test1);
EcrieToto((char**)&test2);
printf("%s\n",test2);
return 0;
}


Unhandled exception at 0x1026f689 (msvcr90d.dll) in testVincent.exe: 0xC0000005: Access violation writing location 0xcccccccc.


Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
13 août 2010 à 17:30
Ce n'est pas pareil !
char** veut dire: un pointeur sur un pointeur (dans ce contexte)
char*[] veur dire: un pointeur sur un tableau contigüe d'élément.

Ce n'est pas compatible, et ton compilateur a du te le dire (tu l'as d'ailleurs ignoré en castant comme un goret ton tableau pour qu'il passe quand même :p).

Voir:
http://www.coders2020.com/what-is-the-difference-between-char-a-and-char-a
http://c-faq.com/decl/strlitinit.html

Ton exemple est bizarre, parce qu'à ta place j'aurais juste fait:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void ecrieToto(char* stValeur)
{
  strcpy(stValeur, "toto");
}

int main(void)
{
  char* test1 = NULL;
  char test2[10];

  test1 = malloc(sizeof(char) * 10);

  ecrieToto(test1);
  printf("%s\n", test1);
  free(test1);

  ecrieToto(test2);
  printf("%s\n", test2);

  return 0;
}


PS: Attention ! Si tu dois caster le retour de malloc c'est qu'il y a 99% de chance que tu utilises un compilateur de C++. Le C et le C++ sont deux langages différents. Tu ne peux pas compiler du C avec un compilo C++ (il y a en C des choses inexistantes ou différentes par rapport au C++, et vice-versa).

________________________________________________________________________
Historique de mes créations, et quelques articles:[ http://0217021.free.fr/portfolio
http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
13 août 2010 à 17:33
Oupss... Je ne réponds pas clairement à ta question:

Une explication ici:
http://www.generation-nt.com/difference-entre-char-str-et-char-str-entraide-201664.html


________________________________________________________________________
Historique de mes créations, et quelques articles:[ http://0217021.free.fr/portfolio
http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
13 août 2010 à 17:44
Oui mon test est blizzard (forcément c'est un test, ET JE SUIS PAS UN GORET, SI JE FAIT SA C'EST QUE J'AI MES RAISONS ) c'est un test (tu aurais peut être préférer ma fonction de 80 lignes avec des affectations mémoire dans tout les sens, des tableaux de structures, j'en passe et des meilleur )

Bon, je me calme et je lit quand même le lient d'explication que tu m'envoie

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
0
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
13 août 2010 à 17:49
Bà si, dans 95% des cas on peut compiler du C en C++ je viens d'ailleurs de faire évoluer un projet dans ce sens (ou donne moi un exemple pck moi j'en trouve pas). Le plus souvent des warning en C devienne des erreurs en C++ (comme quand on passe de VS6 -> VS2008) mais il suffis de ne pas être un goret.
Par contre oui passé du C++ au C n'est pas toujours possible (même rarement).

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
0
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
13 août 2010 à 17:54
Heeeeeeeee le 2ème lient (ni même les 1érs) que tu m'envoie n'a rien à voir avec ma question. Je ne cherche pas à modifier une chaine de caractère fixe défini dans le code mais bien une variable (car oui si je tape <*(&"toto") = 'a';> sa vas planté ma chaine est stocké dans la zone mémoire réservé à mon exe donc en lecture seul.


Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
13 août 2010 à 18:01
forcément c'est un test

Ce n'était pas précisé.

ET JE SUIS PAS UN GORET, SI JE FAIT SA C'EST QUE J'AI MES RAISONS

Inutile de s'énerver. Je t'ai simplement fait remarquer que contourner le compilateur ce n'était pas propre, pas que tu étais un goret. Qui plus est, maintenant que tu as précisé que c'était un simple test, je comprends tout à fait la raison de cette ligne. Il n'y avait pas de volonté de te blesser, et c'est toujours avec plaisir que je réponds sur ce forum.

Bà si, dans 95% des cas on peut compiler du C en C++ je viens d'ailleurs de faire évoluer un projet dans ce sens (ou donne moi un exemple pck moi j'en trouve pas).

Par exemple le mot clé restrict, qui n'est pas présent en C++ (uniquement sous la forme d'extension sur certains compilateurs, donc non portable).
Quelques exemples supplémentaires ici:
http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B

PS: Je fait moi aussi plein de fautes d'orthographe, mais remplace au moins tes "sa" par des "ça".

________________________________________________________________________
Historique de mes créations, et quelques articles:[ http://0217021.free.fr/portfolio
http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
0
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
13 août 2010 à 18:07
Pour finir (puis je part en week end je serais plus détendu lundi) si ce n'est vraiment pas compatible pk sa, sa marche ? :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void EcrieToto(char** stValeur);
void EcrieToto(char** stValeur)
{
strcpy(*stValeur,"toto");
}

int main(int argc, char* argv[])
{
char* test1;
char test2[10];
test1 = test2;
EcrieToto(&test1);
printf("%s\n",test2);
return 0;
}


Aller bon week end quand même (évite de me dire que ce n'est pas la penne d'allouer 10 carac pour en stocké 5 sa vas encore m'énerver. Je deviens susceptible une fois qu'on m'a insulter)

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
0
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
13 août 2010 à 18:26
Aller je me calme (moi aussi je prend tj plaisir à être sur ce fofo pour posé des questions ou y répondre )

Vue, oui C -> C++ effectivement peut poser des problèmes, mais sa reste quand même limité (dans les 5% quoi ) .
Je me rend bien conte que ce wiki n'est pas de toi c'est juste pour en parlé pas pour râlé

Les conversions implicite sont résolut facilement (c'est pas un Warning en C possible)
Les variables nommées class, new, template, en C ne vont pas marché en C++ c'est logique (le mieux étant de tj mettre des entête au nom de variable le problème ne se pose jamais si on est propre, "plnClass" pour un pointeur sur long nommé class par exemple ^^)
Pour le "return sizeof(T);" je voie pas trop l'intérêt de faire sa en C, de toute façon il aurais fallut faire "sizeof(struct T)" (ou mettre un typedef).
Le link oui sa je dit rien je me suis un peut cassé les dents dessus durant ma conversion. Enfin maintenant que je sait comment faire sa ne poseras plus de problème.
Et puis voila ^^

restrict en C Tiens connais pas (c'est pas pour les collections sa ???)

Enfin bref aller cette fois bon week end (Starcraft II m'attend )

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
13 août 2010 à 18:37
restrict en C Tiens connais pas (c'est pas pour les collections sa ???)

C'est surtout pour faire de l'optimisation en posant des contrats sur certains pointeurs (du genre: "Mr le compilateur, je vous promets que je ne ferais pas d'alias de ce pointeur").
http://en.wikipedia.org/wiki/Restrict

Enfin bref aller cette fois bon week end (Starcraft II m'attend )

De même ^^

________________________________________________________________________
Historique de mes créations, et quelques articles:[ http://0217021.free.fr/portfolio
http://0217021.free.fr/portfolio]
Merci d'utiliser Réponse acceptée si un post répond à votre question
0
Polack77 Messages postés 1098 Date d'inscription mercredi 22 mars 2006 Statut Membre Dernière intervention 22 octobre 2019 1
16 août 2010 à 09:37
Ok donc en final c'est une "erreur" d'interprétation du code dans ce cas (qui est un peut spécial c'est vrais )
Merci pour cette explication et bon développement

Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
0
Rejoignez-nous