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


von Der F. (zotos)


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

von Karl H. (kbuchegg)


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.


von Der F. (zotos)


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.
1
  enum { max_zeile=40, max_command=10, max_command_len=20 };
2
3
  struct struct_command 
4
  {
5
    char command_cut[max_command_len];
6
  };
7
8
  static unsigned char zeile[max_zeile+1];
9
10
  struct struct_command command[max_command];
11
  unsigned char command_count;
12
  unsigned char command_offset;
13
14
  unsigned char for_count;
15
16
//------------------------------------------------------------------
17
// Ausschnitt
18
//------------------------------------------------------------------
19
20
        for (for_count = 0;for_count < max_command ;for_count++)
21
        {
22
          command[for_count].command_cut[0] = 0;   
23
        }
24
        command_count = 0;
25
        command_offset = 0;
26
        sprintf (zeile,"%s ", zeile); /* quick and dirty */
27
        /* TODO (#1#): Leerzeichen (Token) Handling verbessern:
28
                             führende und doppelte leerzeichen ignorieren.  */
29
        
30
        for(for_count=0;(zeile[for_count] != 0);for_count++)
31
        {
32
          if (command_count < max_command)
33
          {
34
            if (zeile[for_count] != 32)
35
            {
36
              command[command_count].command_cut[command_offset] = zeile[for_count];                             
37
              command_offset++;
38
            } else {
39
              command[command_count].command_cut[command_offset] = 0;
40
              command_offset = 0;                    
41
              command_count++;
42
            }
43
          }
44
        }

  

von Karl H. (kbuchegg)


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)
1
const char* argv[max_command];
2
int   argc;
3
4
  ...
5
6
  argc = 0;
7
  char* Token = strtok( zeile, " \t" );
8
9
  while( Token != NULL && argc < max_command - 1) { 
10
    argv[argc++] = Token;
11
    Token = strtok( NULL, " \t" );
12
  }
13
  argv[argc] = NULL;
14
15
  ...
16
  //
17
  // und damit kann dann eine Funktion aufgerufen werden
18
  //
19
  foo( argc, argv );

  

von Der F. (zotos)


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.

von Karl H. (kbuchegg)


Lesenswert?

Hier ein mitlerweile getestetes Program
1
#include "stdafx.h"
2
#include "string.h"
3
4
#define max_command 40
5
6
const char* argv[max_command];
7
int   argc;
8
9
void foo1( int argc, const char* argv[] )
10
{
11
  while( *argv != NULL ) {
12
    printf( "*%s*\n", *argv );
13
    argv++;
14
  }
15
  printf( "\n" );
16
}
17
18
void foo2( int argc, const char* argv[] )
19
{
20
  for( int i = 0; i < argc; ++i )
21
    printf( "*%s*\n", argv[i] );
22
  printf( "\n" );
23
}   
24
25
int main()
26
{
27
  char zeile[] = "Dies ist   ein Test";
28
29
  argc = 0;
30
  char* Token = strtok( zeile, " \t" );
31
32
  while( Token != NULL && argc < max_command - 1) { 
33
    argv[argc++] = Token;
34
    Token = strtok( NULL, " \t" );
35
  }
36
  argv[argc] = NULL;
37
38
  foo1( argc, argv );
39
  foo2( argc, argv );
40
41
  return 0;
42
}

  

von Der F. (zotos)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.