C: Variable Anzahl von Strings einlesen und verket

Moin,

wie man eine variable Zahl von Strings verkettet habe ich mittlerweile rausgefunden (über die stdarg.h und alles was so dazu gehört). Mein Problem ist nun: Auch in diesem Fall muss ich schon während des Programmierens wissen, wieviele Strings ich verketten möchte. Zwar nicht in der Funktion selbst, aber immerhin im Aufruf der Funktion. Wie könnte ich mir diese Anzahl offen lassen und soviele Strings verketten, wie über scanf während der Laufzeit eingelesen werden? (Meinetwegen mit Obergrenze 10 Strings, falls nötig)

Nochmal anders:
Wie kriege ich in folgendem Fragment

char\* strings\_verketten( char \*first, ... );
char\* strings\_verketten( char \*first, ...){}
strings\_verketten( "hello", "world", "blabla" )

die konstanten strings „hello“,… ersetzt durch eine variable Anzahl von strings (die z.B. über scanf „reinkommt“)?

thx
moe.

Wie könnte ich mir diese
Anzahl offen lassen und soviele Strings verketten, wie über
scanf während der Laufzeit eingelesen werden? (Meinetwegen mit
Obergrenze 10 Strings, falls nötig)

char buffer[1024];
char\* mein\_string = NULL;

while(42) {
 char\* tmp;
 int ret;

 ret = read( 0, buffer, 1023 );
 if( ret 

Keine variable Anzahl von Argumenten, kein scanf.

Ganz nett, beantwortet aber leider meine Frage nicht. Ich versuche nicht ein Problem zu lösen, sondern C zu lernen. Danke trotzdem.

thx
moe.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Ganz nett, beantwortet aber leider meine Frage nicht. Ich
versuche nicht ein Problem zu lösen, sondern C zu lernen.

Dann versuch dabei, so weit wie möglich von mindestens zwei Dingen fernzubleiben:

  • varargs
  • Funktionen, die in einen Puffer schreiben, ohne dass dabei die Puffergröße übergeben wird.

Nebenbei: warum versuchst du, C zu lernen? Willst du an Betriebssystemen rumschrauben?

Ganz nett, beantwortet aber leider meine Frage nicht. Ich
versuche nicht ein Problem zu lösen, sondern C zu lernen.

Dann versuch dabei, so weit wie möglich von mindestens zwei
Dingen fernzubleiben:

  • varargs

mal sehen. Bisher hatte ich noch kein Problem, dass ich damit lösen wollte, aber in meinem „Skript“ kommt das Thema eben vor.

  • Funktionen, die in einen Puffer schreiben, ohne dass dabei
    die Puffergröße übergeben wird.

Scheinbar bin ich noch nicht weit genung, um zu verstehen, was das überhaupt heisst :wink:

Nebenbei: warum versuchst du, C zu lernen? Willst du an
Betriebssystemen rumschrauben?

Als Basis für C++

moe.

  • varargs

mal sehen. Bisher hatte ich noch kein Problem, dass ich damit
lösen wollte, aber in meinem „Skript“ kommt das Thema eben
vor.

Lass es einfach. Die Dinger machen mehr Probleme als sie lösen.

  • Funktionen, die in einen Puffer schreiben, ohne dass dabei
    die Puffergröße übergeben wird.

Scheinbar bin ich noch nicht weit genung, um zu verstehen, was
das überhaupt heisst :wink:

char buffer[5];

sscanf( "1234567890", "%s", buffer );
/\* rate mal, was grade mit deinem Stack passiert ist... \*/

Nebenbei: warum versuchst du, C zu lernen? Willst du an
Betriebssystemen rumschrauben?

Als Basis für C++

Das ist ein großer Fehler. C++ ist nicht C mit OO obendrauf! C++ sieht nur so ähnlich aus, ist aber eine ganz andere Sprache mit einer sehr brauchbaren Standardbibliothek. Wenn es dir nur um C++ geht, dann lass C komplett aus.

using std::string;
using std::cin;
using std::getline;

string mein\_string, tmp;

while( cin ) {
 getline( cin, tmp );
 mein\_string += tmp;
}

Hallo

Wie könnte ich mir diese Anzahl offen lassen und soviele
Strings verketten, wie über scanf während der Laufzeit
eingelesen werden?

Das sind ja zwei verschiedene Sachen.

  • beliebige String-Anzahl über scanf einlesen
  • gelesene Strings verketten

Einlesen über scanf ist so eine Sache,
Nicos hat richtig angemrkt, dass man das
nicht in richtigem Code macht - allerdings
bin ich der Meinung, dass man es trotzdem
können können sollte :wink:

Scanf liefert jedes „gescannte“ Feld zurück,
indem es dieses auf einen (bereitgestellten)
Zeiger kopiert, also:

 char \*str1, \*str2, \*str3;
 scanf( "%s %s %s", str1, str2, str3 );

Letzendlich werden die zeiger „von rechts nach links“
auf den Stack gelegt (C-Konvention), so dass str1 „oben“
und str3 „unten“ steht.

Wenn man jetzt ein Feld von Zeigern

 char \*vielezeiger[SEHRVIELE]

genauso auf den stack bekommen würde:

 scanf( "%s %s %s", vielezeiger );

könnte man hinterher die gescannten Felder
in vielezeiger[0], vielezeiger[1] usw.
erhalten. Das geht in C/C++ nicht, weil
Arrays [] grundsätzlich nur per Startadresse
übergeben werden, scanf(…) würde also
scheitern, da lediglich ein Zeiger auf den
Stack gelegt wird, die Variable „vielezeiger“.

Wir wollen aber SEHRVIELE Zeiger auf dem
Stack haben, also müssen wir das Array in
eine Struct kapseln, da diese „by value“,
also komplett auf den Stack geht:

struct { char \*vielezeiger[SEHRVIELE]; } kapsel;
scanf( "%s %s %s", kapsel );

Natürlich muss man die konkreten Zeiger,
in die etwas kopiert werden soll, entsprechend
mit Speicher ausreichender Größe versehen.

Ich hab mal ein lauffähiges Beispiel gebastelt,
welches unter Win/Dos gehen sollte (unter Unix-shell
nicht, so lange F6 aka CTRL-Z aka „end of stream“
bereits von der Shell belegt ist.

Da scanf so viele Elemente konvertieren möchte,
wie es Formatzeichen findet, muss man es hier
explizit auffordern, damit aufzuhören (F6 ENTER):

#include "assert.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"

 #define MAXARGS 128
 #define MAXARGLEN 128

 typedef struct { char \*zeile[MAXARGS]; } PTSTRUCT;

// - - - - - - - - - - - - - - - - - - - - - - - - - - //

 void prepare\_scanf\_ride(PTSTRUCT\* pztab, char\*\* format, char item[])
{
 int i;

 \*format = malloc( (strlen(item)+1) \* MAXARGS \* sizeof(char) );
 assert(\*format != 0); 
 (\*format)[0] = '\0';

 for(i=0; izeile[i] = malloc( (MAXARGLEN+1) \* sizeof(char) );
 assert( pztab-\>zeile[i] != 0 ); 
 }
}

 void cleanup\_scanf\_mess(PTSTRUCT\* pztab, char\*\* format)
{
 int i;
 for(i=0; izeile[i] );
 free( \*format );
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - //

 int main(int argc, char\*argv[])
{
 int i, nfelder;
 char\* format;
 PTSTRUCT zeilenzeigerer;

 prepare\_scanf\_ride(&zeilenzeigerer, &format, "%s");

 printf("Worte eingeben, (Abschluss mit F6 [CTRL-Z] - ENTER)\n$\> ", MAXARGS);
 nfelder = scanf(format, zeilenzeigerer);
 
 printf("ok, das waren %d Dinge\n", nfelder);
 for(i=0; i %s\n", i+1, zeilenzeigerer.zeile[i]);

 cleanup\_scanf\_mess(&zeilenzeigerer, &format);

 return 0;
}

Grüße

CMБ

Hallo moe,

wie man eine variable Zahl von Strings verkettet habe ich
mittlerweile rausgefunden (über die stdarg.h und alles was so
dazu gehört). Mein Problem ist nun: Auch in diesem Fall muss
ich schon während des Programmierens wissen, wieviele Strings
ich verketten möchte. Zwar nicht in der Funktion selbst, aber
immerhin im Aufruf der Funktion. Wie könnte ich mir diese
Anzahl offen lassen und soviele Strings verketten, wie über
scanf während der Laufzeit eingelesen werden? (Meinetwegen mit
Obergrenze 10 Strings, falls nötig)

Nochmal anders:
Wie kriege ich in folgendem Fragment

char* strings_verketten( char *first, …){}
strings_verketten( „hello“, „world“, „blabla“ )

die konstanten strings „hello“,… ersetzt durch eine variable
Anzahl von strings (die z.B. über scanf „reinkommt“)?

Es gibt nur eine Lösung: Du musst die ANzahl parameter mit übergeben:

char\* strings\_verketten( **int numargs, char \*first, ...){}  
strings\_verketten( 3, "hello", "world", "blabla" )**  

Das wird auch so beu printf()/scanf() so gemacht. Nur ist die Parameteranzahl halt etwas versteckt. Die Information über die ANzahl und das Format der einzelnen Parametern ist im Formatierungsstring versteckt.

MfG Peter(TOO)

Hallo moe,

wie man eine variable Zahl von Strings verkettet habe ich
mittlerweile rausgefunden (über die stdarg.h und alles was so
dazu gehört). Mein Problem ist nun: Auch in diesem Fall muss
ich schon während des Programmierens wissen, wieviele Strings
ich verketten möchte. Zwar nicht in der Funktion selbst, aber
immerhin im Aufruf der Funktion. Wie könnte ich mir diese
Anzahl offen lassen und soviele Strings verketten, wie über
scanf während der Laufzeit eingelesen werden? (Meinetwegen mit
Obergrenze 10 Strings, falls nötig)

Nochmal anders:
Wie kriege ich in folgendem Fragment

char* strings_verketten( char *first, …){}
strings_verketten( „hello“, „world“, „blabla“ )

die konstanten strings „hello“,… ersetzt durch eine variable
Anzahl von strings (die z.B. über scanf „reinkommt“)?

Es gibt nur eine Lösung: Du musst die ANzahl parameter
mit übergeben:

char* strings_verketten( int numargs, char
*first, …){}
strings_verketten( 3, „hello“, „world“,
„blabla“ )

Das wird auch so beu printf()/scanf() so gemacht. Nur ist die
Parameteranzahl halt etwas versteckt. Die Information über die
ANzahl und das Format der einzelnen Parametern ist im
Formatierungsstring versteckt.

Wenn ich die Anzahl der Strings aber dem Benutzer (zur Laufzeit) überlassen, dann kenne ich sie doch während der Programmierung nicht. Es sei denn, Du sagst mir, wie ich die Strings zähle. Und dann wiederum eine variable Anzahl von Strings in der Parameter-Liste von „Strings_verketten()“ einsetze. Womit wir wieder bei meiner Ausgangsfrage wären :wink:

thx
moe.

Wenn ich die Anzahl der Strings aber dem Benutzer (zur
Laufzeit) überlassen, dann kenne ich sie doch während der
Programmierung nicht. Es sei denn, Du sagst mir, wie ich die
Strings zähle. Und dann wiederum eine variable Anzahl von
Strings in der Parameter-Liste von „Strings_verketten()“
einsetze. Womit wir wieder bei meiner Ausgangsfrage wären :wink:

Dein Beispiel hat diesen Punkt aber nicht gerade erhellt.

Wenn die Grenzen bestimmbar sind, kannst du ein array verwenden:

char array[10][100]; //10 Stings mit maximal 99 Zeichen plus '\0'

Wenn das ganze nur durch den verfügbaren Hauptspeicher begrenzt sein soll musst du dich mal mit malloc()/calloc() vertraut machen und das ganze vernünftig im Speicher anordnen, z.B. mit einer verketteten Liste.

typedef struct \_element
 {
 struct \_element \*next;
 char text[]; // manche compiler mögen das so nicht
 } element;

element \*basis = NULL;

void einfügen( char \*string)
 {
 element \*temp;

 temp = malloc(strlen(string) + 1 + sizeof(\*element));
 if ( temp == NULL )
 {
 // Fehler behandeln ........
 }
 temp-\>next = basis;
 basis = temp;
 strcpy(temp-\>text, string);
 }
(Code ist nicht geprüft)

damit kannst du die Strings verketten, bis der Speicher platzt.

MfG Peter(TOO)

Wenn ich die Anzahl der Strings aber dem Benutzer (zur
Laufzeit) überlassen, dann kenne ich sie doch während der
Programmierung nicht. Es sei denn, Du sagst mir, wie ich die
Strings zähle. Und dann wiederum eine variable Anzahl von
Strings in der Parameter-Liste von „Strings_verketten()“
einsetze. Womit wir wieder bei meiner Ausgangsfrage wären :wink:

Dein Beispiel hat diesen Punkt aber nicht gerade erhellt.

Wenn die Grenzen bestimmbar sind, kannst du ein array
verwenden:

char array[10][100]; //10 Stings mit maximal 99 Zeichen plus
‚\0‘

Wenn das ganze nur durch den verfügbaren Hauptspeicher
begrenzt sein soll musst du dich mal mit malloc()/calloc()
vertraut machen und das ganze vernünftig im Speicher anordnen,
z.B. mit einer verketteten Liste.

typedef struct _element
{
struct _element *next;
char text[]; // manche compiler mögen das so nicht
} element;

element *basis = NULL;

void einfügen( char *string)
{
element *temp;

temp = malloc(strlen(string) + 1 + sizeof(*element));
if ( temp == NULL )
{
// Fehler behandeln …
}
temp->next = basis;
basis = temp;
strcpy(temp->text, string);
}
(Code ist nicht geprüft)

damit kannst du die Strings verketten, bis der Speicher
platzt.

Also entweder hab ich’s nicht verstanden, oder es ist nicht das, was ich meinte :wink:

Ich versuche:

  • über scanf eine unbestimmte Zahl Strings einzulesen
  • diese unbestimmte Zahl Strings zu verketten.
  • dachte eigentlich über varargs(), aber davon wurde mir hier abgeraten
  • möglichst ohne „Umwege“ wie verkettete Listen, etc.
  • falls das überhaupt so geht :wink:

thx
moe.

P.S.: Nicht wegen dieses konkreten Problems, sondern um herauszufinden, wie/ob es das methodisch lösen lässt, tatsächlich mit einer variablen Anzahl von Argumenten zu arbeiten, oder ob tatsächlich _immer_ schon während des Programmierens die Anzahl der Argumente bekannt sein muss.

Ich versuche:

  • über scanf eine unbestimmte Zahl Strings einzulesen
  • diese unbestimmte Zahl Strings zu verketten.
  • dachte eigentlich über varargs(), aber davon wurde mir hier
    abgeraten
  • möglichst ohne „Umwege“ wie verkettete Listen, etc.
  • falls das überhaupt so geht :wink:

Schmeiß C in die Ecke, geh direkt zu C++ und schau dir std::stringstream an.

Hallo moe,

P.S.: Nicht wegen dieses konkreten Problems, sondern um
herauszufinden, wie/ob es das methodisch lösen lässt,
tatsächlich mit einer variablen Anzahl von Argumenten zu
arbeiten, oder ob tatsächlich _immer_ schon während des
Programmierens die Anzahl der Argumente bekannt sein muss.

OK, JETZT wird klar was du wissen willst.

Die Antwort ist ganz klar JAIN !! :wink:)

  1. Also, du kannst eine Funktion **schreiben, welche eine variable Anzahl von Parametern akzeptiert. Allerdings muss dieser Funktion über einen Parameter mitgeteilt werden, wieviele Parameter übergeben werden. Damit die klappt, muss mindestens der erste Parameter immer vorhanden sein. Vergleiche hierzu printf() usw.

  2. Mit Standard-C muss beim Aufruf die Parameter-Anzahl schon bei der Compilierung bekannt sein !!
    Praktisch kann man, falls der Compiler spezielle Erweiterungen zur Stackmanipulation bereit hält, man den Stackaufbau genau kennt oder mit Assembler arbeitet, auch erst zur Laufzeit die Parameteranzahl festlegen. Allerdings ist dieser Code dann …

  1. … garantiert nicht portierbar
  2. … führt im Fehlerfall zu einem programmcrash der übelsten Sorte.
  3. … führt schon zu Abstürzen, wenn andere Compiler-Einstellungen verwendet werden (z.B. Debug-Modus, optimierungen).

Stackmanipulationen lassen sich nur nicht vermeiden, wenn man ein Betriebssystem schreibt. Allerdings ist das dort auch nur auf ein paar wenige Punkte, wie z.B. den Scheduler begrenzt. Hier findet man bei mir auch die einzigen Assembler-Zeilen um die Register zu pushen und popen und natürlich um den Stackpointer umzuschalten.

MfG Peter(TOO)**

Hallo

P.S.: Nicht wegen dieses konkreten Problems, sondern um
herauszufinden, wie/ob es das methodisch lösen lässt,
tatsächlich mit einer variablen Anzahl von Argumenten zu
arbeiten, oder ob tatsächlich _immer_ schon während des
Programmierens die Anzahl der Argumente bekannt sein muss.

Natürlich ist alles möglich, aber irgendwie hast Du bisher
versäumt, konkret und am Beispiel darzulegen, was genau
und wie genau eingelesen werden soll (wie soll das aus-
sehen) - und was soll hinterher konkret rauskommen; was
soll die „Verkettung“ am Ende konkret erbringen.

Grüße

CMБ