Posté le 27/11/2019 15:12
Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 128 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements
Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd
Citer : Posté le 06/04/2022 23:33 | #
Exact, mais std::array t’empêche a coup sur d’écrire au delà de la limite du tableau.
Je sais pas si tous les compilateurs C sont capables de voir a la compilation ce genre de problème avec int tableau standard
Citer : Posté le 06/04/2022 23:38 | #
Si tu spécifies la taille, oui :
{
// ...
}
int sum_of_array_2(std::array<int,10>)
{
// ...
}
mais bien sûr aucun compilateur ne peut décider si le résultat d'un calcul va sortir des bornes.
Citer : Posté le 07/04/2022 02:01 | #
Ha par contre ça m'embête ce que vous venez de dire, parce que moi je voulais faire un truc dans ce style là, mais si j'ai bien compris ça va pas marcher :
int * load_Array(unsigned char *path)
{
FILE *fp = fopen((const char*)path, "r");
int size;
fread(&size, sizeof size, 1, fp);
int * array = new int[size];
fread(array, sizeof *array, size, fp);
fclose(fp);
return array;
}
Albert Einstein
Citer : Posté le 07/04/2022 08:09 | #
Dans ce cas le plus simple pour toi serait peut être de créer une structure qui contient la taille et les data :
{
int size;
int *data; // ou int data[];
};
myArray * load_Array(unsigned char *path)
{
FILE *fp = fopen((const char*)path, "r");
myArray *data = new myArray;
int size;
fread(&size, sizeof size, 1, fp);
int * array = new int[size];
fread(array, sizeof *array, size, fp);
fclose(fp);
data->size = size; // on rempli la structure
data->data = array;
return data; // et on la retourne
}
// ou récupérer les données
myArray *myData = load_Array("Data.dat");
// ... on utilise les données de la structure
// via les membres de celle-ci, par exemple
for( int k=0; k<myData->size; k++)
{
// on bricole avec les données
myData->data[k] *= 10; // Dummy code : on multiplie chaque valeur par 10
}
//penser à libérer avec les delete
delete [] myData->data; // désallouer les données en premier pour ne pas tuer le pointeur vers celles-ci
delete myData; // ensuite la structure
j'ai pas testé et fait ça à la va vite, mais tu comprends le principe. Faudra certainement debugger un peu, Lephe sait taper du code juste directement, mais pas moi
Sinon, comme tu sembles être en C++ (opérateur new), je te conseille vraiment de passer par la STL avec ses containers (effectivement comme écrit par Lephé, dans ce cas un std::vector serait très certainement le meilleur choix). Si tu as besoin, on peut t'aider à utiliser µSTL dans ton projet. Dis nous juste.
Sly
Citer : Posté le 07/04/2022 08:51 | #
Ha par contre ça m'embête ce que vous venez de dire, parce que moi je voulais faire un truc dans ce style là, mais si j'ai bien compris ça va pas marcher :
int * load_Array(unsigned char *path)
{
FILE *fp = fopen((const char*)path, "r");
int size;
fread(&size, sizeof size, 1, fp);
int * array = new int[size];
fread(array, sizeof *array, size, fp);
fclose(fp);
return array;
}
Si, parfait, ça c'est bon. array ne connaît pas sa taille, mais toi tu la connais (c'est size), donc tout va bien
Citer : Posté le 07/04/2022 09:27 | #
Si, parfait, ça c'est bon. array ne connaît pas sa taille, mais toi tu la connais (c'est size), donc tout va bien
Et du coup tu récupères la taille indirectement en dehors de la fonction avec un truc du genre.
int SizeOutOf = sizeof(data)/sizeof(int);
C'est ça ? car sinon la taille (contenue dans 'size') ne sort pas du scope de la fonction load_Array().
Citer : Posté le 07/04/2022 09:53 | #
Merci pour l’explication Lephenixnoir, c’est plus clair comme ça
Citer : Posté le 07/04/2022 10:08 | #
Et du coup tu récupères la taille indirectement en dehors de la fonction avec un truc du genre.
int SizeOutOf = sizeof(data)/sizeof(int);
C'est ça ? car sinon la taille (contenue dans 'size') ne sort pas du scope de la fonction load_Array().
Noooon. Tu récupères la taille comme ça :
int *data = load_Array("Data.dat", &size);
//...
int * load_Array(unsigned char *path, int *size_ptr)
{
FILE *fp = fopen((const char*)path, "r");
int size;
fread(&size, sizeof size, 1, fp);
int * array = new int[size];
fread(array, sizeof *array, size, fp);
fclose(fp);
*size_ptr = size;
return array;
}
Tu fais bien de le mentionner, j'avais pas remarqué que la taille était perdue après.
N'oubliez pas : sizeof n'est qu'une coquille vide que le compilateur remplace par l'espace mémoire occupée par la valeur ou le type indiqué. Le compilateur n'existe plus à l'exécution, il est incapable de donner la taille du tableau si la taille n'est connue qu'à l'exécution. sizeof(...) c'est toujours une constante absolue, quoi qu'il arrive, donc si tu comptes utiliser sizeof() pour obtenir un résultat non constant (par exemple, qui dépend du contenu d'un fichier) c'est triplement impossible.
Alors c'est quoi sizeof(array) tu vas me dire ? C'est la taille du pointeur menant au tableau, ie. 4. Et c'est là la différence absolue entre int array[8] et int *ptr. Les deux sont plus ou moins équivalents dans la façon dont on les utilise (et si tu écris array tout seul il est «affaibli» en int *, ce qui est source de pas mal de confusion), mais les deux types sont différents, le premier a un sizeof de 32 et le second a un sizeof de 4.
Ton code ci-dessus donne une taille de 1 dans tous les cas.
Citer : Posté le 07/04/2022 11:34 | #
Effectivement c'était pas clair dans ma tête non plus.
C'est vraiment hyper piégeur ces notions de tableaux/pointeurs. On a vraiment vite fait de faire une boulette.
Et du coup mon code avec la structure, c'est viable ou pas ?
Citer : Posté le 07/04/2022 11:39 | #
Oui absolument. Attention int data[] dans la définition de la structure c'est différent - ça met les données à la fin de la structure, ce qui te donne une structure dont la taille est variable et que tu alloues d'un seul coup avec malloc. int *data c'est plus simple.
Je serais juste tenté de passer la structure par valeur plutôt que de l'allouer dans le tas, mais bon c'est un détail.
Idéalement autant passer à la STL si c'est du C++, comme tu l'as dit.
Citer : Posté le 07/04/2022 19:12 | #
alors j'ai essayer ta fonction et ça n'a pas marché, je me retrouve avec une liste interminable, avec des valeurs qui ne sont pas correct du style :
(ces tests on été fait sur pc)
16777216 33554432 50331648 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451.....
Albert Einstein
Citer : Posté le 07/04/2022 19:22 | # | Fichier joint
J'ai mis en pièce jointe les fichiers de tests
Albert Einstein
Citer : Posté le 07/04/2022 19:40 | #
Tu sauvegardes en big-endian, ce qui est correct pour la calculatrice, mais le PC est little-endian. C'est normal que ça ne marche pas.
Citer : Posté le 08/04/2022 01:21 | #
Ha ok merci pour l'info.
sinon j'aimerai refaire la même chose que les codes d'avant avec des unsigned char* et des unsigned char**.
En gros j'aimerai sauvegarder et lire une chaines de caractère et un tableau de chaines de caractère :
var1 = "exemple"
var2 = ["exemple1","exemple2"]
Alors j'ai regarder la docu des struct donc pour var1 ça devrai être facile car c'est comme un tableau d'entier je supposes (en changeant '>i' par '>B'), mais pour var2 qui est un tableau de tableau, là je ne sais pas trop comment m'y prendre.
(à noté que dans les deux cas, le script ne connais pas la taille de var1 et de var2, ni la longueur des éléments de var2. Il faudra donc utilisé la technique que tu m'a montré je supposes)
Albert Einstein
Citer : Posté le 08/04/2022 09:11 | #
Bienvenue dans le monde de la sérialisation. Pour un format binaire comme ça, ultimement tu peux procéder ainsi :
longueur | première chaîne | deuxième chaîne
| longueur | données | longueur | données
Citer : Posté le 08/04/2022 16:11 | #
Alors du coup j'ai essayer de faire un truc dans le genre :
Python :
def SaveArrayOfString(fp,lst):
for i in lst:assert(type(i)==str)
#assert(type(fp)==_io.BufferedWriter)
fp.write(struct.pack('>i', len(lst)))
for i in lst:
fp.write(struct.pack('>i', len(i)))
fp.write(b''.join(struct.pack('>B', n) for n in str.encode(i)))
C++ :
unsigned char** DeserializeArrayOfString(FILE* fp,int *size_ptr) {
int size;
fread(&size, sizeof size, 1, fp);
*size_ptr = size;
unsigned char** array = new unsigned char* [size];
for (int i = 0; i < size; i++)
{
int sizeSTR;
fread(&sizeSTR, sizeof sizeSTR, 1, fp);
unsigned char* str = new unsigned char[sizeSTR];
fread(str, sizeof * str, sizeSTR, fp);
array[i] = str;
}
return array;
}
....
int count = 1;
unsigned char** testText;
int size;
FILE* fp;
if (fp = fopen((const char*)"textSave.bin", "r")) {
testText = DeserializeArrayOfString(fp, &size);
}
for (int i = 0; i < size; i++)
{
dtext(0,i*20,C_WHITE,testText[i]);
}
ça affiche bien le texte mais ça rajoute des lettres en plus à chaque lignes. (des u et des s uniquement)
Albert Einstein
Citer : Posté le 08/04/2022 16:14 | #
Oui, impeccable. N'oublie juste pas que la représentation en mémoire d'une chaîne de caractères, en C, doit se terminer par un NUL (un octet de valeur zéro).
Donc au lieu de :
fread(str, sizeof * str, sizeSTR, fp);
Il faut bien penser à ajouter le NUL :
fread(str, sizeof * str, sizeSTR, fp);
str[sizeSTR] = '\0';
Citer : Posté le 08/04/2022 16:20 | #
Ho ça marche ! Parfait merci, Nickel !
Mais du coup quand je vais libéré la mémoire, est-ce que je dois libéré chaque élément un à un :
for(int i=0;i<size;i++){
delete testText[i];
}
delete[] testText;
ou juste faire:
delete[] testText;
parce que je ne comprends pas bien comment fonctionne les delete
Albert Einstein
Citer : Posté le 08/04/2022 16:26 | #
Excellente question. La règle d'or c'est : chaque new/new[] doit correspondre à exactement un delete/delete[], et donc la réponse c'est le premier.
new/delete c'est exactement comme malloc()/free(), si tu es familier avec ça∞.
Sinon, c'est pas très dur : chaque new ou new[] réserve de la mémoire pour une valeur ou un tableau de valeurs, et te donne un pointeur vers la mémoire réservée. Chaque delete ou delete[] rend (on dit "libère") la mémoire en question.
Au moment où tu fais delete[] testText, tu libères le tableau de pointeurs. Mais les pointeurs originaux pointent toujours vers de la mémoire réservée, parce que c'est pas "transitif" ! Et en plus après delete[] testText tu n'as plus le droit de lire testText[i], donc comme tu l'as justement écrit il faut bien libérer les éléments du tableau en premier.
(Plus généralement : en C++, new et delete invoquent aussi les constructeurs et destructeurs. Les constructeurs et destructeurs sont des fonctions quelconques et peuvent faire n'importe quoi. Par exemple, la plupart des objets vont libérer la mémoire de leur variables internes quand tu fais delete dessus. Donc quand tu as des vrais objets C++, il devient important de comprendre qui est responsable de libérer chaque allocation pour s'assurer que toute la mémoire est libérée. Mais avec des variables classiques du C comme des tableaux, c'est toujours toi qui es responsable de tout.)
Citer : Posté le 08/04/2022 16:36 | #
Alors justement, parce que ce que tu as dis c'est ce que je pensais avant mais je me suis embrouillé avec cette fonction :
void GameManager::LoadMap(int index) {
char path[20];
sprintf(path, "DATA_RPG/%d.MAP", index);
FILE* fp;
fp = fopen((const char*)path, "r");
.....
fclose(fp);
};
Je voulais libérer path après le fclose(fp), donc j'ai essayer delete[] et delete, les deux ne marchaient pas. Enfin si, delete[] marche qu'une fois, c'est à dire que je l'appel une fois elle marche, je la rappel à nouveau elle marche plus. (et quand il a pas de delete[] ça marche à tous les coups)
Albert Einstein
Citer : Posté le 08/04/2022 16:41 | #
Ici path n'est pas alloué sur le tas (malloc()/new/new[]), c'est juste une variable locale allouée sur la pile. Comme le int index que tu as en paramètre ou le int sizeSTR de la fonction plus haut. Tu n'as pas besoin de la libérer.
Cheat sheet :
// Données (20 octets) sur la pile, pas de libération
char *path = malloc(20);
// Le pointeur (4 octets) est sur la pile, les données (20 octets) dans le tas
free(path);
char *path = new char;
// Le pointeur (4 octets) est sur la pile, la donnée (1 octet) dans le tas
delete path;
char *path = new char[20];
// Le pointeur (4 octets) est sur la pile, les données (20 octets) dans le tas
delete[] path;