mikrocontroller.net

Forum: Compiler & IDEs argc und **argv aus Textzeile ermitteln


Autor: Der Fönig (zotos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich würde gerne aus einer Textzeile argc (Argumenten Zähler) und **argv 
(Argumenten Vektor) ermitteln. Damit ich das ganze an eine andere 
Funktion übergeben kann.

Das ganze soll darauf hinauslaufen das ich eine Textzeile 
(Kommandozeile) via UART rein bekomme und dann in ein Zweidimensionales 
Char  Array (quasi ein String Array) wandle. Damit ich die Argumente wie 
vom PC gewöhnt in meiner Funktion verwenden kann.

Ich habe das auch schon von Hand zu Fuß am laufen.
Würde aber gerne mit strtok_r arbeiten und bekommen das nicht gebacken.

Gruß vom Fönig

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Fönig wrote:

> Das ganze soll darauf hinauslaufen das ich eine Textzeile
> (Kommandozeile) via UART rein bekomme und dann in ein Zweidimensionales
> Char  Array (quasi ein String Array) wandle.

Achtung:
Das original an main() übergebene argv ist kein 2D Array,
sondern ein Array aus Pointern auf char-Arrays.

> Ich habe das auch schon von Hand zu Fuß am laufen.
> Würde aber gerne mit strtok_r arbeiten und bekommen das nicht gebacken.

Zeig doch mal was du hast dann kann man auch mal analysieren
wo denn die Probleme konkret liegen.


Autor: Der Fönig (zotos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:
> Zeig doch mal was du hast dann kann man auch mal analysieren
> wo denn die Probleme konkret liegen.

Schn der Ansatz gefällt mir aber nicht.
  enum { max_zeile=40, max_command=10, max_command_len=20 };

  struct struct_command 
  {
    char command_cut[max_command_len];
  };

  static unsigned char zeile[max_zeile+1];

  struct struct_command command[max_command];
  unsigned char command_count;
  unsigned char command_offset;

  unsigned char for_count;

//------------------------------------------------------------------
// Ausschnitt
//------------------------------------------------------------------

        for (for_count = 0;for_count < max_command ;for_count++)
        {
          command[for_count].command_cut[0] = 0;   
        }
        command_count = 0;
        command_offset = 0;
        sprintf (zeile,"%s ", zeile); /* quick and dirty */
        /* TODO (#1#): Leerzeichen (Token) Handling verbessern:
                             führende und doppelte leerzeichen ignorieren.  */
        
        for(for_count=0;(zeile[for_count] != 0);for_count++)
        {
          if (command_count < max_command)
          {
            if (zeile[for_count] != 32)
            {
              command[command_count].command_cut[command_offset] = zeile[for_count];                             
              command_offset++;
            } else {
              command[command_count].command_cut[command_offset] = 0;
              command_offset = 0;                    
              command_count++;
            }
          }
        }

  

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist ne ganz schöne Umkopiererer.
Du sagtest, dass deine Routinen ein argc/argv Handling
haben, woraufhin ich darauf hingewiesen habe, dass argv
kein 2D Array sondern ein Array von Pointern darstellt.

Der Unterschied ist: Deine Lösung sieht im Speicher
so aus:

  command
  +---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+
  |   |   |   |   |   |   |   |
  +---+---+---+---+---+---+---+


während die argv Lösung so aussieht:

   argv
   +-----+      +---+---+---+
   | o--------->|   |   |\0 |
   +-----+      +---+---+---+         +---+---+---+---+
   | o------------------------------->|   |   |   |\0 |
   +-----+      +---+---+---+---+     +---+---+---+---+
   | o--------->|   |   |   |\0 |
   +-----+      +---+---+---+---+     +---+---+
   | o------------------------------->|   |\0 |
   +-----+      +---+---+---+         +---+---+
   | o--------->|   |   |\0 |
   +-----+      +---+---+---+         +---+---+---+
   | o------------------------------->|   |   |\0 |
   +-----+      +---+---+---+---+     +---+---+---+
   | o--------->|   |   |   |\0 |
   +-----+      +---+---+---+---+
   |NULL |
   +-----+

Nun sagt aber niemand, dass die Arrayfetzelchen rechts
alle unterschiedliche Arrays sein müssen. Die Pointer
können durchaus alle in dasselbe Array zeigen (die
aufgerufene Funktion, main(), hat sowieso kein Recht
im argv irgendwelche Manipulationen durchzuführen):


               +---+---+---+---+---+---+---+---+---+---+---+---+
               |   |   |\0 |   |\0 |   |   | \0|   |   |\0 |   |
               +---+---+---+---+---+---+---+---+---+---+---+---+
               ^           ^       ^           ^
   +-----+     |           |       |           |
   |  o--------+           |       |           |
   +-----+                 |       |           |
   |  o--------------------+       |           |
   +-----+                         |           |
   |  o----------------------------+           |
   +-----+                                     |
   |  o----------------------------------------+
   +-----+
   |NULL |
   +-----+

Hintergrund der ganzen Storry: Dieses grosse Array hast du ja
bereits. Es ist dein 'Zeile' Array. Alles was du noch tun musst
um ein argv zu implementieren ist ein Array von Pointern
aufzusetzen, welche in dieses Array hineinzeigen. Und natürlich
müssen im 'Zeile' Array noch die \0 eingefügt werden um die
jeweiligen String Enden zu markieren.

Zum Aufsetzen des Arrays kommt jetzt strtok() ins Spiel.
Es zeigt sich, dass strtok() eine dafür perfekt passende Aktion
macht:
* strtok() sucht nach dem ersten Zeichen, welches nicht als Trenn-
  zeichen angegeben wurde. Diese Position wird als Pointer
  retourniert und markiert den Beginn des Tokens
* strtok() sucht nach dem Ende des Tokens, indem es solange den
  String weiterliest, bis eines der Trennzeichen auftaucht.
  Dieses Zeichen wird durch ein '\0' Zeichen ersetzt.
* strtok() liefert NULL wenn es keinen Token mehr identifizieren
  konnte.

(ungetesteter Code)
const char* argv[max_command];
int   argc;

  ...

  argc = 0;
  char* Token = strtok( zeile, " \t" );

  while( Token != NULL && argc < max_command - 1) { 
    argv[argc++] = Token;
    Token = strtok( NULL, " \t" );
  }
  argv[argc] = NULL;

  ...
  //
  // und damit kann dann eine Funktion aufgerufen werden
  //
  foo( argc, argv );


  

Autor: Der Fönig (zotos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:
> Das ist ne ganz schöne Umkopiererer.
> Du sagtest, dass deine Routinen ein argc/argv Handling
> haben, woraufhin ich darauf hingewiesen habe, dass argv
> kein 2D Array sondern ein Array von Pointern darstellt.

Ich bin platt.

Super Erklärung!

Vielen viel Dank.

Ich mach mich gleich dran das zu testen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier ein mitlerweile getestetes Program
#include "stdafx.h"
#include "string.h"

#define max_command 40

const char* argv[max_command];
int   argc;

void foo1( int argc, const char* argv[] )
{
  while( *argv != NULL ) {
    printf( "*%s*\n", *argv );
    argv++;
  }
  printf( "\n" );
}

void foo2( int argc, const char* argv[] )
{
  for( int i = 0; i < argc; ++i )
    printf( "*%s*\n", argv[i] );
  printf( "\n" );
}   

int main()
{
  char zeile[] = "Dies ist   ein Test";

  argc = 0;
  char* Token = strtok( zeile, " \t" );

  while( Token != NULL && argc < max_command - 1) { 
    argv[argc++] = Token;
    Token = strtok( NULL, " \t" );
  }
  argv[argc] = NULL;

  foo1( argc, argv );
  foo2( argc, argv );

  return 0;
}

  

Autor: Der Fönig (zotos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es läuft und das genau so wie ich mir das Vorgestellt habe ;o)

Nochmal vielen Dank nicht nur für die Lösung sondern auch für die 
Erklärungen dazu.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.