Passage d'un tableau de tableaux en paramètre d'une fonction

Bonsoir
Je cherche à écrire une fonction qui va lire sur un site Internet des citations, ainsi que leurs auteurs. Ça fonctionne sur un ESP32.

Lorsque j’écris tout dans la loop, ça marche bien. Voici le code et ce qu’il fournit.

#include <WiFi.h>
#include <HTTPClient.h>
const char* ssid       = "Lesept";
const char* password   = "xxxx";

void setup () {
  Serial.begin (115200);
  //connect to WiFi
  int wifiCounter = 0;
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (++wifiCounter > 30) ESP.restart(); // restart after 15 s
  }
  Serial.println(" CONNECTED");
}

void Accents (int &c) {
  if (c >= 224 && c <= 230) c = 97;
  else if (c == 231) c = 99;
  else if (c >= 232 && c <= 235) c = 101;
  else if (c >= 236 && c <= 239) c = 105;
  else if (c == 241) c = 110;
  else if (c >= 242 && c <= 246) c = 111;
  else if (c >= 249 && c <= 252) c = 117;
}

void loop()
{
  WiFiClient *pStream;
  HTTPClient http;

  http.begin("https://dicocitations.lemonde.fr/citations-jour.php");
  if (http.GET() == HTTP_CODE_OK)
  {
    pStream = http.getStreamPtr();
    while (pStream->find("color=\"black\"><b>"))
    {
      Serial.println();
      int c = pStream->read();
      char Citation[256] = {0};
      int nCit = 0;
      Citation[nCit] = c & 0xFF;
      while (c != 60 && nCit < 256) {
        c = pStream->read();
        Accents (c);
        Citation[++nCit] = c & 0xFF;
      }
      Citation[nCit] = '\0';
      Serial.println (Citation);

      // Search the author's name
      if (pStream->find("citation d"))
      {
        int c = pStream->read(); // Shift one character
        c = pStream->read();
        if (c == 32) c = pStream->read();
        char Author[50] = {0};
        int nAut = 0;
        Author[nAut] = c & 0xFF;
        while (c != 60 && nAut < 50) { // 50 is the max length for author's name
          c = pStream->read();
          Accents (c);
          Author[++nAut] = c & 0xFF;
        }
        Author[nAut] = '\0';
        Serial.println (Author);
      }
    }
  }
  else Serial.println("Unable to connect to server!");
  http.end();
  delay(10000);
}

Il s’etait fait aimer par elle comme il savait se faire aimer. Il avait cueilli sans peine son ame legere de poupee.
Maupassant

Les couvertures des livres sont des portes qui donnent, non sur des textes arides comme on le croit souvent, mais sur de fabuleux univers.
Anne Liger-Belair dite Gudule

Nous sommes toujours censes regarder vers le futur. Mais en vieillissant, il est beaucoup plus facile de regarder en arriere et de regretter amerement les erreurs du passe.
Mary Higgins Clark

La liberte n’est pas de faire ce qu’on veut, mais ce qu’on a le droit de faire.
Victor Cousin

Dans le combat humain pour l’elevation de l’esprit, il ne suffit pas de monter le plafond, il faut aussi empecher le plancher de s’effondrer.
Bernard Werber

Un pessimiste voit la difficulte dans chaque opportunite, un optimiste voit l’opportunite dans chaque difficulte.
Churchill

C’etait un specialiste de l’immobilier. Il avait connu des tas de maisons: maisons de correction, maisons d’arret, maisons centrales.
Blaise Cendrars

A tous les repas pris en commun, nous invitons la liberte a s’asseoir. La place demeure vide mais le couvert est mis.
Rene Char

Je ne sais pas tres bien ce que je cherche. Mais je sais ce dont je ne veux pas.
Jules Romains

En politique, la verite est un luxe inutile.
Philippe Alexandre

Les utilisateurs de Facebook ne sont que des hommes-sandwichs qui travaillent gratuitement. Ce serait stupide de ne pas les utiliser.
Joel Dicker

De tous les vices, la sagesse est encore le plus agreable.
Edouard Herriot

La fantaisie n’est pas l’oppose de l’intelligence. La fantaisie est l’intelligence appliquee a etablir des rapports d’analogie, d’implication significative, de symbolisme.
Cesare Pavese

Opera : Piece representant la vie dans un autre monde, dont les habitants n’ont pas de discours mais des chansons, pas de mouvements mais des gestes, pas de postures mais des attitudes.
Ambrose Bierce

Des femmes sont des maitresses; d’autres, des amantes; d’autres des amies. Les maitresses se remplacent; les amantes, rarement; les amies, jamais.
Remy de Gourmont

Comme il renvoie plusieurs couples {citation, auteur}, je voudrais en afficher une seule choisie au hasard, et ceci à la demande. Donc je veux mettre les citations dans un tableau de citations et les auteurs dans un tableau d’auteurs (ou un tableau de structures {citation, auteur}).

Enfin, il faut que tout ça soit dans une fonction pour être intégré dans un programme plus grand.
Le problème est de définir dans la loop mes deux tableaux:

  char Citation[maxNbCitations][sizeCitation] = {0};
  char Author[maxNbCitations][sizeAuthor] = {0};

avec plus haut

#define sizeCitation 256
#define sizeAuthor 50
#define maxNbCitations 20

et de remplir ces tableaux dans une fonction

int getCitations (char * Citation, char * Author)

qui me renvoie le nombre de citations lues sur le site (max 20).

J’ai déjà du mal avec les arguments passés par référence, mais avec les tableaux je suis perdu !!!
Voici mon code : il plante, probablement un dépassement de taille de tableau (les messages d’erreur de l’ESP32 sont parfois abscons) : quelqu’un peut me dire ce que j’ai mal codé ?

#include <WiFi.h>
#include <HTTPClient.h>
#define sizeCitation 256
#define sizeAuthor 50
#define maxNbCitations 20
const char* ssid       = "Lesept";
const char* password   = "xxx";

void setup () {
  Serial.begin (115200);
  //connect to WiFi
  int wifiCounter = 0;
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (++wifiCounter > 30) ESP.restart(); // restart after 15 s
  }
  Serial.println(" CONNECTED");
}

void Accents (int &c) {
  if (c >= 224 && c <= 230) c = 97;
  else if (c == 231) c = 99;
  else if (c >= 232 && c <= 235) c = 101;
  else if (c >= 236 && c <= 239) c = 105;
  else if (c == 241) c = 110;
  else if (c >= 242 && c <= 246) c = 111;
  else if (c >= 249 && c <= 252) c = 117;
}

int getCitations (char * Citation, char * Author) {
  int nCit = 0;
  WiFiClient *pStream;
  HTTPClient http;
  http.begin("https://dicocitations.lemonde.fr/citations-jour.php");
  if (http.GET() == HTTP_CODE_OK)
  {
    pStream = http.getStreamPtr();
    while (pStream->find("color=\"black\"><b>") && nCit < maxNbCitations)
    {
      Serial.println();
      int c = pStream->read();
      int nChar = 0;
      *(Citation + nChar + nCit * sizeCitation) = c & 0xFF;
      while (c != 60 && nChar < sizeCitation) {
        c = pStream->read();
        if (c > 223) Accents (c);
        Serial.print((char)(c & 0xFF));
        *(Citation + (++nChar) + nCit * sizeCitation) = c & 0xFF;
      }
      *(Citation + nChar + nCit * sizeCitation) = '\0';

      // Search the author's name
      if (pStream->find("citation d"))
      {
        int c = pStream->read(); // Shift one character
        c = pStream->read();
        if (c == 32) c = pStream->read();
        int nAut = 0;
        *(Author + nAut + nCit * sizeAuthor) = c & 0xFF;
        while (c != 60 && nAut < sizeAuthor) {
          c = pStream->read();
          if (c > 223) Accents (c);
          Serial.print((char)(c & 0xFF));
          *(Author + (++nAut) + nCit * sizeAuthor) = c & 0xFF;
        }
        *(Author + nAut + nCit * sizeAuthor) = '\0';
      }
      Serial.println ();
      //      Serial.printf ("%d : %s - %s\n", nCit, Author, Citation);
      nCit++;
    }
  }
  else Serial.println("Unable to connect to server!");
  http.end();
  return nCit;
}


void loop() {
  char Citation[maxNbCitations][sizeCitation] = {0};
  char Author[maxNbCitations][sizeAuthor] = {0};
  int nCit = getCitations (*Citation, *Author);
  for (int i = 0; i < nCit; i++) {
    Serial.println (Citation[i]);
    Serial.println (Author[i]);
  }
  delay(10000);
}

Merci :slight_smile:

Désolé, c’est peu commenté : je peux ajouter des commentaires pour expliquer si nécessaire…

Salut

Au niveau mémoire: 20 citations, chacune ayant 256+50= 306 caractères réservés = ~6 Kilo Octets. Sur un ESP32 ça ne posera pas de pb.

Le soucis dans votre code est ici:

getCitations (*Citation, *Author)

(il faut relire mon tuto sur les pointeurs). L'opérateur * va chercher le contenu pointé donc *Citation ou *Author c'est le premier octet du tableau.

vous pouvez juste passer Citation et Author directement mais vous pourriez aussi les garder en variables globales et ne pas vous ennuyer... En effet c'est un tableau à 2 dimensions et quand vous le passez en paramètre en C, il ne connait plus les dimensions. Donc c'est effectivement à vous de calculer la ligne et colonne pour rajouter du contenu (ce n'est pas très compliqué puisque vous connaissez les tailles donc pour un caractère en Citation[l][c] son indice est l*sizeCitation + c comme vous le faites)

bref - essayez votre code en appelantgetCitations (Citation, Author); et changez la signature de la fonctionint getCitations (char Citation[maxNbCitations][sizeCitation], char Author[maxNbCitations][sizeAuthor]) {les accès deviennent alors

      *(Citation[nCit] + nChar) = c & 0xFF;
...
        *(Citation[nCit] + (++nChar)) = c & 0xFF;
...
      *(Citation[nCit] + nChar) = '\0';

et idem pour Author (si vous voulez utiliser les pointeurs, sinon comme on a déclaré en tableau, vous pouvez directement accédé au caractère par ses indices)

Bonjour,

Si le tableau transmis à getCitations a toujours la même dimension tu peux le préciser dans la définition
getCitations (_Citation[maxNbCitations][sizeCitation],_Author[maxNbCitations][sizeAuthor])

Tu peux ainsi tester la taille dans la fonction

Personnellement, je pense qu'un tableau de structures serait plus approprié
De plus plutot que des tables de caractères de taille fixe, l'utilisation de pointeur avec allocation dynamique ferait sans doute gagner de la place.

L'allocation dynamique fera gagner de la place, au risque du morcellement de la mémoire cependant. Autant réserver tout l'espace dont on pourrait avoir besoin dans le cas général et ne pas se soucier de l'allocation... sur un ESP pour un programme aussi simple il n'y a pas trop besoin de se casser la tête

Cependant quand vous remplissez le tableau il faut vraiment tester si le nombre de caractères lus ne dépasse pas sizeCitation-1 ou sizeAuthor-1 et le nombre de citation ne dépasse pas maxNbCitations

Dans le cas particulier je pense que le tableau de citations ne sera jamais vidé.
Dans le cas contraire il faudrait relacher la mémoire dans l'ordre inverse des affectations, ce qui n’occasionnera aucune fragmentation de mémoire (pour autant qu'il n'y ait pas d'allocation dynamique ailleurs)

Merci à vous deux, je vais tester ça.

Pour ce qui est de la mémoire : je n'ai jamais fait d'allocation dynamique.
Ce bout de code est fait pour s'insérer dans un programme plus gros qui tournera en permanence avec pas mal de mise en sommeil profond. Ces tableaux seront mis en mémoire RTC de l'ESP32, avec des infos de météo.

Je mettrai ces infos à jour avec une périodicité variable pour éviter de me connecter trop souvent à Internet et trop décharger la batterie. Par exemple, prévisions météo horaires : toutes les 3 heures, prévisions météo quotidiennes, toutes les 6 heures et citations & saint du jour toutes les 24 heures.

Donc toutes les 24 heures je mettrai ces tableaux à jour.
Est-ce bon côté mémoire ?

lesept:
Pour ce qui est de la mémoire : je n'ai jamais fait d'allocation dynamique.

si vous voulez voir comment affecter de la mémoire dynamiquent, j'avais mis un exemple dans mon tuto sur les pointeurs

Par rapport à ce que vous décrivez - le site web envoyant chaque jour une citation différente, vous n'avez pas vraiment besoin de vous embêtez à en lire plein pour en prendre une au hasard, vous pouvez vous contenter de prendre la première donnée par le site... Si vous voulez la changer dans la journée en fonction de l'heure par exemple, alors là charger le tableau peut être intéressant

Ca ne marche pas : l’ESP plante. J’ai ajouté des print pour voir jusqu’où il va.
J’obtiens 2 ‘OK’ et il plante

Voici le code :

int getCitations (char Citation[maxNbCitations][sizeCitation], char Author[maxNbCitations][sizeAuthor]) {
  int nCit = 0;
  WiFiClient *pStream;
  HTTPClient http;
  Serial.println("OK");
  http.begin("https://dicocitations.lemonde.fr/citations-jour.php");
  Serial.println("OK");   // <--- jusque là, ça va...
  if (http.GET() == HTTP_CODE_OK)
  {
    Serial.println("OK");   // <--- ça plante ici !!!
    pStream = http.getStreamPtr();
    while (pStream->find("color=\"black\"><b>") && nCit < maxNbCitations)
    {
      Serial.println(nCit);
      int c = pStream->read();
      int nChar = 0;
      //     *(Citation + nChar + nCit * sizeCitation) = c & 0xFF;
      *(Citation[nCit] + nChar) = c & 0xFF;
      while (c != 60 && nChar < sizeCitation - 1) {
        c = pStream->read();
        if (c > 223) Accents (c);
        Serial.print((char)(c & 0xFF));
        //        *(Citation + (++nChar) + nCit * sizeCitation) = c & 0xFF;
        *(Citation[nCit] + (++nChar)) = c & 0xFF;
      }
      //      *(Citation + nChar + nCit * sizeCitation) = '\0';
      *(Citation[nCit] + nChar) = '\0';

      // Search the author's name
      if (pStream->find("citation d"))
      {
        int c = pStream->read(); // Shift one character
        c = pStream->read();
        if (c == 32) c = pStream->read();
        int nAut = 0;
        //        *(Author + nAut + nCit * sizeAuthor) = c & 0xFF;
        *(Author[nCit] + nAut) = c & 0xFF;
        while (c != 60 && nAut < sizeAuthor - 1) {
          c = pStream->read();
          if (c > 223) Accents (c);
          Serial.print((char)(c & 0xFF));
          //          *(Author + (++nAut) + nCit * sizeAuthor) = c & 0xFF;
          *(Author[nCit] + (++nAut)) = c & 0xFF;
        }
        //        *(Author + nAut + nCit * sizeAuthor) = '\0';
        *(Author[nCit] + nAut) = '\0';
      }
      Serial.println ();
      Serial.printf ("%d : %s - %s\n", nCit, Author[nCit], Citation[nCit]);
      nCit++;
    }
  }
  else Serial.println("Unable to connect to server!");
  http.end();
  return nCit;
}


void loop() {
  char Citation[maxNbCitations][sizeCitation] = {0};
  char Author[maxNbCitations][sizeAuthor] = {0};
  int nCit = getCitations (Citation, Author);
  for (int i = 0; i < nCit; i++) {
    Serial.println (Citation[i]);
    Serial.println (Author[i]);
  }
  delay(10000);
}

Avec mon ancien code, je n’avais pas de problème avec le GET, mais je n’arrivais pas à gérer le tableau…

Si vous voulez la changer dans la journée en fonction de l’heure par exemple, alors là charger le tableau peut être intéressant

Oui, c’est le principe, je veux pouvoir changer la citation affichée sur sollicitation de l’utilisateur.

mettez en commentaire l'écriture dans le tableau pour voir si tout s'imprime bien et remplacez les accès par pointeur par la notation sous forme de tableau pour la lisibilité*(Citation[nCit] + nChar) = c & 0xFF;devientCitation[nCit][nChar] = c & 0xFF;

Même erreur lorsque les écriture tableaux sont commentées.

Je ne sais pas combien d'octets sont disponibles dans la pile. Peut être que les deux tableaux excèdent la taille de la pile.
Essaies de déclarer les tableaux en statique

Je vais essayer de les mettre en variables globales, ce sera le cas de toutes façons au final.

La pile, c'est "heap" ? J'ai trouvé ça pour l'ESP32:

Due to a technical limitation, the maximum statically allocated DRAM usage is 160KB. The remaining 160KB (for a total of 320KB of DRAM) can only be allocated at runtime as heap.

ça répond à ta question ?

La pile ce n'est pas la heap. La heap c'est ce qui est utilisé pour les allocations dynamiques.
Dans la plupart des implémentations le pointeur de pile descend en partant du haut de mémoire et le pointeur de heap monte en partant du bas de la mémoire (au dessus des variables statiques), ce qui fait que théoriquement on devrait pouvoir allouer pour la pile toute la place restant dans la heap.
Mais ça dépend des implémentations.

dans mon tuto sur les pointeurs il y a une petite mention de la pile et le tas

lesept:
Même erreur lorsque les écriture tableaux sont commentées.

donc y’a un bug ailleurs…

Damned !

De mon côté, en passant les tableaux en global et suivant vos suggestions pour le code, ça fonctionne impec ! J'ai parfois un souci avec le "streaming" il semble que parfois certains caractères soient corrompus, mais dans ce cas j'obtiens une citation de longueur 255 que je peux facilement éliminer.

Merci de votre aide !

@J-M-L : je vais lire ton tuto... promis (y'a pas interro j'espère)

lesept:
@J-M-L : je vais lire ton tuto... promis (y'a pas interro j'espère)

:slight_smile: