Bonjour, à la suite d'un petit projet, je dois faire une fonction qui prend en paramètre un tableau d'entier et une valeur (un entier). Le but est de décaler nos valeurs de une place, en d'autre terme, Tab[i] = Tab[i+1] et lors de ma dernière valeur de tableau Tab[i] = valeur.
Voici le code que j'ai pu faire :
int Indice_max_Tableau = 5;
void setup() {
Serial.begin(9600);
int Tab[5] = {1,2,3,4,5};
for (int i=0; i < Indice_max_Tableau;i++){
Serial.println(Tab[i]);
}
int NewTab[5];
int Valeur = 3;
NewTab = Decalage(Tab[], Valeur);
for (int j=0; j < Indice_max_Tableau;j++){
Serial.println(NewTab[j]);
}
}
void loop(){
}
int Decalage(int Tableau[], int Valeur){
for (int i=0; i<Indice_max_Tableau;i++){
Tableau[i] = Tableau[i+1];
}
Tableau[Indice_max_Tableau] = Valeur;
return Tableau;
}
Lors de ma compilation, on me dit que je dois mettre quelque chose entre mes crochets, mais pas moyen de comprendre pourquoi et comment résoudre ce problème.
en C++ on ne passe pas un tableau sans donner sa taille. Si on ne veut pas passer la taille en paramètre, il faut passer un pointeur sur le premier élément du tableau (et ici vous connaissez la taille)
void Decalage(int* Tableau, int Valeur){
for (int i=0; i<Indice_max_Tableau;i++){
Tableau[i] = Tableau[i+1];
}
Tableau[Indice_max_Tableau] = Valeur;
}
vérifiez bien vos indices... quand i vaut 4....
vous ne retournez pas non plus un nouveau tableau, donc le mieux c'est de en rien retourner
@A1one ,
J'espère que @J-M-L ne m'en voudra pas trop d'intervenir sur ce fil où il vient de vous donner la réponse à votre question sans vous donner les détails du code.
1ère version :
int Indice_max_Tableau = 5;
int Valeur = 3;
void setup() {
Serial.begin(9600);
int Tab[Indice_max_Tableau] = {1, 2, 3, 4, 5};
for (int i = 0; i < Indice_max_Tableau ; i++) Serial.print(Tab[i]);
Serial.println("\n");
Decalage(Tab, Valeur);
for (int j = 0; j < Indice_max_Tableau ; j++) Serial.println(Tab[j]);
}
void loop() {}
void Decalage(int *Tableau, int Valeur) {
for (int i = 0; i < Indice_max_Tableau - 1 ; i++) {
Tableau[i] = Tableau[i + 1];
}
Tableau[Indice_max_Tableau - 1] = Valeur;
}
2ème version :
int Indice_max_Tableau = 5;
int Valeur = 3;
void setup() {
Serial.begin(9600);
int Tab[Indice_max_Tableau] = {1, 2, 3, 4, 5};
for (int i = 0; i < Indice_max_Tableau ; i++) Serial.print(Tab[i]);
Serial.println("\n");
Decalage(Tab, Valeur);
for (int j = 0; j < Indice_max_Tableau ; j++) Serial.println(Tab[j]);
}
void loop() {}
void Decalage(int* t, int Valeur) {
int i;
for (i = 0; i < Indice_max_Tableau - 1 ; i++) {
// *(t+i) = *(t+i) + 1;
(*(t + i))++;
}
*(t + i) = Valeur;
}
Bonne journée.
C'est le mec radin d'octets qui parle. Si j'ai un tableau et que je dois changer d'indice toutes les valeurs, je procède ainsi: j'imagine un tableau "circulaire" dont je donne le point de départ. Ainsi décaler le tableau revient simplement à décaler l'origine. Cela donne:
Je définis mon tableau par
byte indiceMaxTableau = 5; // Taille du tableau
byte indiceZeroTableau = 0; // Décalage de l'origine du tableau
int tab[indiceMaxTableau] = {1, 2, 3, 4, 5};
Pour accéder à l'indice "indice" du tableau (au lieu de tab[indice]):
J'avoue qu'un tableau circulaire, ça ne me parle pas du tout !
J'ai plutôt l'habitude des blocs mémoires contigüs.
Je ne vois pas trop ce que viennent faire les modulos dans le code.
Tout au plus j'arrive à tirer ça de vos explications :
Je ne sais pas si c'est à ça que pensait @vileroi , mais je suppose qu'il parle de liste circulaire(ou liste chainée circulaire), qui peut être vue comme un tableau non continue en mémoire d'une certaine manière.
Dans ce cas là tu change la valeur de l'élément précèdent du déplace ton pointeur de début sur cet élément.
Le mieux étant alors d'avoir une liste doublement chainée pour éviter d'avoir trop de déplacement dans la liste.
on peut le faire avec un tableau aussi, c'est comme cela que le buffer du port série par exemple est géré.
@philippe86220 - en fait l'idée c'est d'éviter les mouvements mémoire qui sont couteux en temps CPU (imaginez que le tableau ait 1000 éléments, pour ajouter un élément à la fin vous allez bouger 999 éléments puis en écrire un) et de simplement déplacer le "début" du tableau pour décaler les éléments . Comme le tableau est un espace "non circulaire" le modulo permet de trouver l'élément suivant quand on arrive à la fin
on a l'impression qu'on a donc décalé toutes la valeurs du tableau mais en fait je ne maintiens que le bool qui me dit si le tableau a été rempli et la variable prochaineCase qui me dit où j'en suis dans mon buffer
Dans un tableau linéaire, il y a un indice de début (0) et un indice de fin (indiceMaxTableau-1)
Si on parcourt le tableau en ajoutant 1 ou -1 à l'indice, on finira par pointer en dehors du tableau.
Pour un tableau circulaire, on l'imagine sur un cercle en collant la dernière case à côté de la première. Si on parcourt le tableau arrivé en fin on passe au début. On peut le représenter ainsi:
Si je veux décaler tout le tableau, il suffit d'incrémenter/décrémenter l'indice de départ.
Bien sûr cette représentation n'est pas implantée en C, et on "déroule le tableau pour le coder:
Et on utilise une structure de tableau conventionnelle.
Pour accéder à la case d'indice indice du tableau circulaire, on va à l'adresse indice+indiceDeDepart du tableau linéaire du C. Mais si ce nombre dépasse indiceMaxTableau, on a rebouclé et il faut retirer indiceMaxTableau Cela peut se faire avec le modulo qui donne la bonne valeur que l'on dépasse le tableau linéaire du C d'un côté ou de l'autre.
Le gros intérêt de cette représentation est que l'on n'a pas à décaler les données. Par exemple dans le cas d'un envoi de donnée, on aura un indice de départ et un indice de fin du tableau. On peut remplir le tableau sans toucher aux paramètres qui vide le tableau. Un décalage au mauvais moment risque de dupliquer ou de perdre une valeur.
Non, c'est bien un tableau, et on utilise dessous une structure de tableau. L'intérêt d'une liste est que la taille n'est pas fixe.
Cela devrait donner quelque chose comme (non testé):
Dernière chose, si le tableau à comme dimension 256 valeur, on n'a plus besoin du modulo car le type byte est déja "circulaire": 255+1 donne 0.
Si le tableau est une puissance de 2, on remplace le modulo par un ET bit à bit. par exemple pour un tableau de 8 valeurs:
tab[(j+indiceZeroTableau) && 7]
ça fonctionne pour ce que vous faites mais attention à ne pas tomber dans le piège courant où l'on pense qu'une opération sur un byte va rester sur un byte
essayez ce code
void test(byte v) {
Serial.print("indice direct = "); Serial.println(v + 1);
byte r = v + 1;
Serial.print("indice stocké = "); Serial.println(r);
}
void setup() {
Serial.begin(115200);
byte b = 100;
test(b); // ==> imprime 101 OK
b = 255;
test(255); // ==> imprime 256 !!! on n'a plus un byte !
}
void loop() {}
la norme C++ définit que lorsque l'on a une opération mathématique avec une donnée tenant sur un octet (un byte signé ou pas) alors le byte est promu en entier (donc sur 2 octets ou 4 suivant la plateforme) et l'opération réalisée en entier. C'est pour cela que
Serial.println(v + 1);
va déborder.
Il faut bien s'assurer de stocker le résultat dans un byte avant de faire quoi que ce soit.
Du coup, un nouveau tableau est affiché dans le moniteur série mais cette fois-ci, il démarre à l'indice 4 : ce qui donne : "5972604831". Toujours 10 éléments mais lorsqu'on arrive à l'indice de fin le tableau : "0" grâce au modulo, on repart au premier indice et les 4 derniers éléments sur 10 du nouveau tableau virtuel deviennent les 4 premiers du tableau réel !
Ce nouveau tableau virtuel devient la base de travail :
Notez aussi que modulo est coûteux en temps de calcul sur petit MCU et donc c’est plus efficace de tester si on atteint une extrémité et remettre le compteur à l’autre bout