Shutter String C

dandy

Grünschnabel
Hi Leute ich bereite mich grad auf eine Prüfung vor und bin bei den Angaben von den letzten Jahren auf ein Beispiel gestoßen (sorry für die Textformatierung, habs von nem .pdf kopiert):

Schreiben Sie eine Funktion stutterString, welche einen C-String als Argument übernimmt
und einen Array von C-Strings als Rückgabewert liefert. Aus dem Argument wird eine Reihe
von Strings erzeugt, welche jeweils aus den ersten n Buchstaben des Ausgangsstrings
bestehen, wobei n zwischen 1 und der Stringlänge des Argumentes liegt. Aus dem
„Haus“ wird also „H“, „Ha“, „Hau“, „Haus“ erzeugt.

Schreiben Sie eine Hauptfunktion, welche die Funktion stutterString mit dem String
„Murkraftwerk“ aufruft und das Ergebnis auf der Kommandozeile ausgibt.

Code:
shutterstring(char* str1)
{
  int size1 = strlen(str1);
  int i, j;
  char str_ausgabe[size1][size1];

  for(i = 0; i < size1; i++)
  {
      for(j = 0; j <= i; j++)
      {
          str_ausgabe[i][j] = str1[j];
      }
  }
  return str_ausgabe;
}

int main()
{
  int size1 = strlen("Murkraftwerk");
  char (*ausgabe)[12] = shutterstring("Murkraftwerk");
  int i, j;

  for(i = 0; i < size1; i++)
  {
      for(j = 0; j <= i; j++)
      {
          printf("%c", *(*(ausgabe+i)+j));
      }
      printf("\n");
  }
}

Ich hab da irgendein Problem bei der Rückübergabe an die main-Funktion aber ich check nicht genau was ich falsch gemacht habe..
Vielleicht könnt mir wer einen Tipp geben? =)
Die Deklaration von "ausgabe" in der main scheint mir auch noch nicht ganz richtig zu sein, ich hab jetzt einfach mal für testzwecke die größe mit 12 festgelegt aber da sollt ich auch eine bessere lösung finden.
 
Hallo

In VSC++ 2012 liefert das einen Haufen Fehler.
C:
shutterstring(char* str1)
Funktionstyp fehlt.
C:
char str_ausgabe[size1][size1];
Da war glaube ich mal was in der Richtung mit diesem syntactic sugar, doch sicherer wäre:
C:
char** str_ausgabe = (char**)malloc(size1);
for(int i = 0;i<size1;i++)
{
    str_ausgabe[i] = (char*)malloc(size1);
}
Dann zur "ausgabe":
C:
char (*ausgabe)[12] = shutterstring("Murkraftwerk");
Das ist IMHO nicht schön. Warum nicht
C:
char** ausgabe = shutterstring("Murkraftwerk");
?

Und vergiss nicht, den Speicher am Ende wieder freizugeben.

Gruss
cwriter

/EDIT: Übersehen:
C:
 for(i = 0; i < size1; i++)
  {
      for(j = 0; j <= i; j++)
      {
          printf("%c", *(*(ausgabe+i)+j));
      }
      printf("\n");
  }
Du hast die Strings doch schon umgeschoben, warum also nicht einfach
C:
for(int i = 0; i < size1;i++)
{
    puts(ausgabe[i]);
}
?
 
Zuletzt bearbeitet:
Erstmal danke für die Hilfe, ein paar Sachen sind mir noch ein wenig unklar^^

Code:
char** shutterstring(char* str1)
{
  int size1 = strlen(str1);
  int i, j;
  char** str_ausgabe = (char**)malloc(size1);

  for(i = 0; i<size1; i++)
  {
     *(str_ausgabe+i) = (char*)malloc(size1);
  }

  for(i = 0; i < size1; i++)
  {
      for(j = 0; j <= i; j++)
      {
          str_ausgabe[i][j] = str1[j];
      }
  }
  return str_ausgabe;
}

int main()
{
  int i;
  int size1 = strlen("Murkraftwerk");
  char** ausgabe = shutterstring("Murkraftwerk");

  for(i = 0; i < size1; i++)
  {
      printf("%s\n", *(ausgabe+i));
  }

  free(ausgabe);
  return 0;
}

Das ist jetzt der Code mit deinen Ergänzungen.

Code:
char** shutterstring(char* str1)
Also wenn ich als Funktions-Datentyp einen char** angebe dann krieg ich als Rückgabewert einen char** auf das array das ich mit return zurück gebe oder?

Code:
char** str_ausgabe = (char**)malloc(size1);

  for(i = 0; i<size1; i++)
  {
     *(str_ausgabe+i) = (char*)malloc(size1);
  }
Dieser part ist jetzt nur dafür da, dass ich meinem array Speicherplatz gebe, also size1 Spalten mit jeweils size1 Feldern. Wenn ich schon so genau arbeite sollte ich dann nicht auch schaun dass ich der ersten Zeile nur ein malloc(1) Speicher gebe? Es wird ja bei der ersten Zeile 1 Buchstabe, 2. Zeile - 2 Buchstaben usw. reingespeichert
(ich hab deinen Code da ein bisschen geändert, glaub du hättest 12 mal der selben Adresse speicher gegeben)

Code:
char** str_ausgabe = (char**)malloc(size1);

  for(i = 0; i<size1; i++)
  {
     *(str_ausgabe+i) = (char*)malloc(i+1);
  }

Also so irgendwie?

Code:
 char** ausgabe = shutterstring("Murkraftwerk");

  for(i = 0; i < size1; i++)
  {
      printf("%s\n", *(ausgabe+i));
  }

  free(ausgabe);
  return 0;
Da liegt mein Hauptverständnisproblem, ich krieg also den return Wert von der Funktion zurück und speichere ihn in char** ausgabe. Wie kann ich jetzt auf die einzelnen Strings zugreifen? Der Pointer "ausgabe" von der main zeigt mir ja im Grunde nur auf den Speicher in den ich das array in der Funktion gespeichert habe, oder liege ich da falsch?
 
Wenn ich schon so genau arbeite sollte ich dann nicht auch schaun dass ich der ersten Zeile nur ein malloc(1) Speicher gebe? Es wird ja bei der ersten Zeile 1 Buchstabe, 2. Zeile - 2 Buchstaben usw. reingespeichert

Yup, das wäre der nächste Schritt gewesen.
Also so irgendwie?
Ja. (Später mehr dazu)

Wie kann ich jetzt auf die einzelnen Strings zugreifen? Der Pointer "ausgabe" von der main zeigt mir ja im Grunde nur auf den Speicher in den ich das array in der Funktion gespeichert habe, oder liege ich da falsch?
Das liegst du richtig.
char** ist so aufgebaut (wenn man die erste Dimension als 3 setzt):
Code:
ptr1 ptr2 ptr3
ptr1, ptr2 und ptr3 sind auf 32bit-Systemen 32bit (4 byte) gross.
Durch Iterieren (ausgabe+1 (oder ausgabe[1], ist dasselbe) kommt man an die ptr. Diese zeigen wiederum auf die Anfangsbuchstaben der einzelnen Strings. Alles klar?

So, und nun zum Code: Ich habe mich mal daran versucht und bin kläglich mit einem zerschossenen Heap gescheitert :-(
Da jegliche Stackvariable am Ende des Scopes ({ } = Scope) zerfällt, ist es klüger, den Rückgabewert in einem char*** zu speichern.
C:
char** shutterstring(char* str1, char*** out)
Nun ein Vorschlag: Du findest meinen Fehler und du hast alles, was du brauchst ;-):
C:
 char** shutterstring(char* str1,char*** ausgabe)
{
  int size1 = strlen(str1);
  *ausgabe = (char**)calloc(size1+1,1);
  if(*ausgabe == NULL) return NULL;
  for(int i = 0;i<size1;i++)
  {
	  (*ausgabe)[i] = (char*)calloc(i+2,1);
	  if((*ausgabe)[i] == NULL) return NULL;
	  memcpy_s((*ausgabe)[i],i+1,str1,i+1);
	  for(int j = 0;j<i+2;j++)
	  {
		  if((*ausgabe)[i][j] == (char)0) printf("\\0");
		  else printf("%c",(*ausgabe)[i][j]);
	  }
	  printf("\n");

  }
  //strcpy_s((*ausgabe)[0],2,"M");
  return *ausgabe;
}
 
int main(int argc, char* argv[])
{
  int size1 = strlen("Murkraftwerk");
  char **ausgabe = shutterstring("Murkraftwerk",&ausgabe);
  for(int i = 0;i<size1;i++)
  {
	  printf("%d:%d:%s\n",i,ausgabe+i,(ausgabe[i]));
  }
  system("PAUSE");
  return 0;
}
Der Ansatz: calloc füllt den allozierten Speicher automatisch mit 0en. So muss man das \0 am Ende der Strings nicht mehr anfügen.
Netterweise spuckt mir VSC++ 2012 bei der Ausgabezeile aber in die Suppe und gibt ausgabe[0] falsch aus.

Gruss
cwriter
 
Code:
char** shutterstring(char* str1)
{
  int size1 = strlen(str1);
  int i, j;
  char** str_ausgabe = (char**)malloc(size1);

  for(i = 0; i<size1; i++)
  {
     *(str_ausgabe+i) = (char*)malloc(15);
  }

  for(i = 0; i < size1; i++)
  {
      for(j = 0; j <= i; j++)
      {
          str_ausgabe[i][j] = str1[j];
      }
  }
  return str_ausgabe;
  free(str_ausgabe);
}

int main()
{
  int i, j;
  int size1 = strlen("Murkraftwerk");
  char** ausgabe = shutterstring("Murkraftwerk");

  for(i = 0; i < size1; i++)
  {
      for(j = 0; j <= i; j++)
      {
          printf("%c", ausgabe[i][j]);
      }
      printf("\n");
  }
  free(ausgabe);
  return 0;
}

Soda meine entgültige Lösung (sry das mit den 3er Pointern hab ich einfach nicht kapiert :p )

Also ich geb das ganze jetzt einfach zeichenweise aus. Das Problem bei deiner Lösung ist glaub ich, dass in meiner Angabe steht: "Schreiben Sie eine Funktion stutterString, welche einen C-String als Argument übernimmt
und einen Array von C-Strings als Rückgabewert liefert"
Darum darf ich glaub ich wirklich nur einen String übergeben.

Kannst du mir vielleicht noch ganz kurz durchschaun ob ich da jetzt Speicherlecks oder so drinnen hab, da bin ich mir noch nicht so ganz sicher.

Ansonsten vielen Dank :)
 
C:
*(str_ausgabe+i) = (char*)malloc(15);
Und wenn du einen anderen String hast? Mit anderer Länge?
C:
  return str_ausgabe;
  free(str_ausgabe);
alles nach dem return wird nie ausgeführt...
Array von C-Strings als Rückgabewert liefert"
Du gibst aber streng genommen einen Bytearray zurück. Nullterminiere die Daten, dann hast du deine Strings und kannst direkt puts oder printf("%s") nutzen.

Gruss
cwriter
 
Hi

Es sind noch einige drin, teilweise wurden sie schon weiter oben behandelt.

Zeile 9:
Der Teil vor = ist nicht falsch, aber unnötig umständlich,
und nach = : Warum 15? Warum nicht zB. i+2?
C:
str_ausgabe[i] = (char*)malloc(i+2);

Zeile 17 nach der Klammer (aus der inneren Schleife draußen,
aber in der äußeren noch drin):
C:
str1[j] = '\0';
Sonst weiß man beim Ausgeben nicht, wann Schluss ist.

Zeile 20 ist Unsinn.
a) nach dem return wird das sowieso nie ausgeführt.
b) Wenn, dann wäre es falsch.
Du kannst das hier noch nicht freigeben, weil du das ja im main noch brauchst.
c) Beim malloc-ieren hast du ein Gesamtmalloc und dann pro String im Array noch eins.
Dh. du musst auch wieder in einer Schleife durch free´s machen, vor diesem Gesamt-free.
Aber wie gesagt, nicht an dieser Stelle.

Zeile 31-35 kann wirklich durch
C:
puts(ausgabe[i]);
ersetzt werden.
Sonst machst du die ganze Arbeit ja noch einmal

Und vor Zeile 37 gehört jetzt dieses Schleifen-free.
Oder man macht in der puts-Schleife die free
(das, was gerade ausgegeben wurde,
auch gleich danach freigeben)
 
Hach, sheel :)

Dürfte ich dich - halb OT - darum bitten, den Fehler in meinem Code (post #3) zu finden? Würde er funktionieren, fände ich es mit memcpy schöner als mit dem Durchiterieren (Wir könnten ja auch wieder einen Benchmark schreiben ;-)

Gruss
cwriter
 
Code:
char** shutterstring(char* str1)
{
  int size1 = strlen(str1);
  int i, j;
  char** str_ausgabe = (char**)malloc(size1);

  for(i = 0; i<size1; i++)
  {
     str_ausgabe[i] = (char*)malloc(i+2);
  }

  for(i = 0; i < size1; i++)
  {
      for(j = 0; j <= i; j++)
      {
          str_ausgabe[i][j] = str1[j];
      }
      str_ausgabe[i][j] = '\0';
  }
  return str_ausgabe;
}

int main()
{
  int i;
  int size1 = strlen("Murkraftwerk");
  char** ausgabe = shutterstring("Murkraftwerk");

  for(i = 0; i < size1; i++)
  {
      puts(ausgabe[i]);
      free(ausgabe[i]);
  }
  free(ausgabe);
  return 0;
}

Maan ich verstehs gar nicht mehr :(
Beim debuggen bekomm ich jetzt in der Funktion wenn i=10 einen Segmentation Fault...

Aber ich geb mit:
Code:
 char** str_ausgabe = (char**)malloc(size1);
an dass ich size1 (also 12) Spalten haben will. Ich check nicht warum ich dann bei i=10 einen Fehler krieg...

Wegen dem
Code:
puts(ausgabe[i]);
, da bin ich mir nicht sicher ob wirdie string.h verwenden dürfen aber so ists sicher die elegantere Lösung.
Dienstag Abend ist die Prüfung, das wird noch spannend >.<

Danke euch nochmal für die Hilfe :)
 
Zurück