Char array, bzw string
Hallo, versuche mich an der Programmierung mit C und will jetzt irgendwie eine Funktion schreiben, die mir die Text Eingabe in der Konsole in einem Dynamischen Array speichert, sodass ich nicht unnötig viel Speicher reservieren muss.
Habe es schon hin bekommen, dass es innerhalb der Funktion funktioniert, nur bekomme ich das char array nicht zurück in die main.
Es wird eine Zeile ausgeben, in der der eingegebene String steht (das printf in ZK) und eine Zeile in der L steht, das heist, Test wird nicht in der main überschrieben, sondern nur lokal in der ZK behandelt.
Wie bekomme ich jetzt die Test aus der ZK zurück in die main?
das mit dem return Test, war auch nur ein Test, das will ich so nicht behalten.
Schonmal danke für eine Antwort.
Habe es schon hin bekommen, dass es innerhalb der Funktion funktioniert, nur bekomme ich das char array nicht zurück in die main.
char ZK(char* Test)
{
char Text[1000];
int laeng=0,i,j;
fgets(Text, 1000, stdin);
//printf("%s",Text);
laeng=strlen(Text);
Test=(char*) malloc((laeng+1) * sizeof(char));
for(i=0;i<=laeng;i++){
if(Text[i]!='\n')
Test[i]=Text[i];
else
Test[i]=NULL;
}
//Test[i]='a';
printf("%s",Test);
//printf("\n");
//free(Test);
return *Test;
}
#include "Header.h"
#include "stdlib.h"
#include "stdio.h"
int main(void){
char *Test="L";
printf("Gibt einen Text ein\n");
ZK(Test);
printf("\n");
printf("%s\n",Test);
system("pause");
}
Es wird eine Zeile ausgeben, in der der eingegebene String steht (das printf in ZK) und eine Zeile in der L steht, das heist, Test wird nicht in der main überschrieben, sondern nur lokal in der ZK behandelt.
Wie bekomme ich jetzt die Test aus der ZK zurück in die main?
das mit dem return Test, war auch nur ein Test, das will ich so nicht behalten.
Schonmal danke für eine Antwort.
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 219963
Url: https://administrator.de/contentid/219963
Ausgedruckt am: 24.11.2024 um 18:11 Uhr
8 Kommentare
Neuester Kommentar
Hallo Power-Poler,
C ist bei solchen (vermeintlich einfachen) Dingen etwas für Masochisten (zumal du offenbar Java gewohnt bist). Du bist für die Speicherverwaltung selbst verantwortlich. Das heißt, für eine Eingabe mit dynamischer Länge musst du den verwendeten Speicher auch dynamisch erweitern (malloc, realloc). Das erfordert dann auch ein zeichenweises Einlesen. Die fgetc Funktion hat sich dafür bewährt.
Kommentiertes Beispiel, so wie ich Benutzereingaben für mich definiert und umgesetzt habe:
Falls du statt einem C Compiler einen C++ Compiler verwenden solltest, must du malloc und realloc noch das Casting zum Charpointer voranstellen.
Der Rückgabewert der Funktion ist 0 wenn bei der Eingabe alles OK war.
Grüße
rubberman
C ist bei solchen (vermeintlich einfachen) Dingen etwas für Masochisten (zumal du offenbar Java gewohnt bist). Du bist für die Speicherverwaltung selbst verantwortlich. Das heißt, für eine Eingabe mit dynamischer Länge musst du den verwendeten Speicher auch dynamisch erweitern (malloc, realloc). Das erfordert dann auch ein zeichenweises Einlesen. Die fgetc Funktion hat sich dafür bewährt.
Kommentiertes Beispiel, so wie ich Benutzereingaben für mich definiert und umgesetzt habe:
#include <stdio.h>
#include <stdlib.h>
/* Benutzereingabe als nullterminierten String (ohne Zeilenumbruch) lesen mit dynamischer Speichererweiterung */
int Fn_GetInput(char ** const pszInput_out, size_t * const pcchLength_out)
{
size_t ic = 0; // Index im Puffer - später Anzahl Zeichen
int ch = EOF; // hält später den ASCII Wert des eingelesenen Zeichens
char *szBuffer = malloc(1), *pchMoreSpace = NULL; // Speicher für den Puffer reservieren, Pointer für eine Puffererweiterung deklarieren
if (pszInput_out) *pszInput_out = NULL; // Initialwert
if (pcchLength_out) *pcchLength_out = 0; // Initialwert
if (szBuffer) // wenn malloc() erfolgreich war
{
while ((ch = fgetc(stdin)) != '\n' && ch != EOF && !feof(stdin)) // lese das (nächste) Zeichen, iteriere solang das Zeichen kein Zeilenumbruch ist und nicht das Ende des eingehenden Streams erreicht ist
{
szBuffer[ic++] = ch; // weise das Zeichen der aktuellen Position (ic=Index) im Puffer zu und erhöhe danach um 1 (ic++=nächster Index=Stringlänge)
pchMoreSpace = realloc(szBuffer, ic + 1); // Puffergröße um 1 erweitern
if (!pchMoreSpace) // falls die Erweiterung fehlgeschlagen ist
{
free(szBuffer); // Speicher freigeben
return EXIT_FAILURE; // Fehler, raus hier
}
szBuffer = pchMoreSpace; // neuen Pointer der Variablen szBuffer zuweisen
}
szBuffer[ic] = 0; // Nullterminierung
if (pszInput_out)
*pszInput_out = szBuffer; // Pointer zum Puffer geht nach draußen
else
free(szBuffer); // falls ein Nullpointer übergeben wurde, Speicher freigeben
if (pcchLength_out) *pcchLength_out = ic; // Anzahl eingelesener Zeichen geht nach draußen
}
return (szBuffer == NULL); // 0 (EXIT_SUCCESS) wenn szBuffer nicht NULL
} // ACHTUNG: Reservierten Speicher in der aufrufenden Funktion freigeben!
int main(void)
{
char *szStr = NULL;
size_t cchLen = 0;
if (EXIT_SUCCESS == Fn_GetInput(&szStr, &cchLen)) // Benutzereingabe einholen und auf Verarbeitungsfehler prüfen.
{
printf("\nFn_GetInput:\n Laenge: %u\n String: %s\n", cchLen, szStr); // Anzeigen, was wir bekommen haben.
free(szStr); // Speicher (reserviert in Fn_GetInput()) freigeben, sobald szStr nicht länger benötigt wird!
return EXIT_SUCCESS;
}
fprintf(stderr, "Fn_GetInput: Verarbeitungsfehler.\n");
return EXIT_FAILURE;
}
Der Rückgabewert der Funktion ist 0 wenn bei der Eingabe alles OK war.
Grüße
rubberman
Hallo Power-Poler.
Grüße
rubberman
(Sieht man das an meinen Quellcode, dass ich mich vorher an Java versucht habe ?)
Nee, deinen früheren Postings aber ähhm da muss ich mich erst einmal rein arbeiten
Jepp. Ich hoffe du kannst mit meinen Kommentaren was anfangen. Bei Unklarheiten, einfach melden.(Oh Gott, da liegt ja scheinbar noch einiges vor mir, bis ich C kann... )
Ich arbeite nur ab und an mit C. Von "können" kann also bei mir auch nach 2 Jahren nicht die Rede sein. Ich habe mich damals dazu entschieden C zu lernen wegen der Performance und der einfachen Handhabung der Windows API. Aber ob ich von Java auf C umsteigen würde ...? Wohl noch eher auf C++, dann bleibt dir wenigstens die Objektorientierung erhalten (auch wenn das dort noch mal was ganz anderes ist).Grüße
rubberman
Hi Power-Poler,
wenn du schon C++ programmieren willst, so nutze doch einfach das String-Objekt.
http://www.willemer.de/informatik/cpp/string.htm
Gruß
Günni
wenn du schon C++ programmieren willst, so nutze doch einfach das String-Objekt.
http://www.willemer.de/informatik/cpp/string.htm
Gruß
Günni
Ja, scanf funktioniert zu dem Zweck schon auch. Aus Spaß mal eine etwas ausführlichere Möglichkeit mit strtol (in das Beispiel von oben eingebaut). Kannst ja mal versuchen ob du folgen kannst, Kommentare sind wieder dabei.
Die Fn_GetLong gibt eine Bitmaske als unsigned int zurück, in der einzelne Fehlerflags gesetzt werden. Diese kannst du verarbeiten und später in deinem Programm selbst entscheiden welche Eingaben du als gültig akzeptierst.
Grüße
rubberman
#include <stdio.h> // Fn_GetInput
#include <stdlib.h> // Fn_GetInput, Fn_GetLong
#include <string.h> // Fn_GetLong
#include <ctype.h> // Fn_GetLong
#include <errno.h> // Fn_GetLong
/* Benutzereingabe als nullterminierten String (ohne Zeilenumbruch) lesen mit dynamischer Speichererweiterung */
int Fn_GetInput(char ** const pszInput_out, size_t * const pcchLength_out)
{
size_t ic = 0; // Index im Puffer - später Anzahl Zeichen
int ch = EOF; // hält später den ASCII Wert des eingelesenen Zeichens
char *szBuffer = malloc(1), *pchMoreSpace = NULL; // Speicher für den Puffer reservieren, Pointer für eine Puffererweiterung deklarieren
if (pszInput_out) *pszInput_out = NULL; // Initialwert
if (pcchLength_out) *pcchLength_out = 0; // Initialwert
if (szBuffer) // wenn malloc() erfolgreich war
{
while ((ch = fgetc(stdin)) != '\n' && ch != EOF && !feof(stdin)) // lese das (nächste) Zeichen, iteriere solang das Zeichen kein Zeilenumbruch ist und nicht das Ende des eingehenden Streams erreicht ist
{
szBuffer[ic++] = ch; // weise das Zeichen der aktuellen Position (ic=Index) im Puffer zu und erhöhe danach um 1 (ic++=nächster Index=Stringlänge)
pchMoreSpace = realloc(szBuffer, ic + 1); // Puffergröße um 1 erweitern
if (!pchMoreSpace) // falls die Erweiterung fehlgeschlagen ist
{
free(szBuffer); // Speicher freigeben
return EXIT_FAILURE; // Fehler, raus hier
}
szBuffer = pchMoreSpace; // neuen Pointer der Variablen szBuffer zuweisen
}
szBuffer[ic] = 0; // Nullterminierung
if (pszInput_out)
*pszInput_out = szBuffer; // Pointer zum Puffer geht nach draußen
else
free(szBuffer); // falls ein Nullpointer übergeben wurde, Speicher freigeben
if (pcchLength_out) *pcchLength_out = ic; // Anzahl eingelesener Zeichen geht nach draußen
}
return (szBuffer == NULL); // 0 (EXIT_SUCCESS) wenn szBuffer nicht NULL
} // ACHTUNG: Reservierten Speicher in der aufrufenden Funktion freigeben!
/* C-String zu Long Integer */
unsigned Fn_GetLong(const char * const szNum_in, const int iBase_in, long * const pNum_out)
{
char *szCpy = NULL, *szTrunc = NULL, *pchEnd = NULL; // szCpy bekommt eine Kopie von szNum_in, szTrunc bekommt einen Pointer zum ersten Zeichen in szCpy das kein Whitespace ist, der Variablen pchEnd wird strtol() den Pointer zuweisen, an dem die Verarbeitung abgebrochen wurde
unsigned rgbitRet = 0; // zurückgegebene Fehlerbits
if (pNum_out) *pNum_out = 0; // Initialwert
if (!szNum_in || !pNum_out || iBase_in < 0 || iBase_in > 36 || iBase_in == 1) return 8; // wenn einer der übergebenen Pointer NULL ist oder iBase_in nicht zwischen 0 und 36 liegt bzw. 1 ist, Fatal Error und raus hier
szCpy = malloc(strlen(szNum_in) + 1); // Speicher für szCpy reservieren
if (!szCpy) return 8; // wenn malloc() fehlgeschlagen ist, Fatal Error und raus
szTrunc = strcpy(szCpy, szNum_in); // String kopieren, um nicht über ein Cast letztlich doch im als konstant deklarierten Speicherbereich von szNum_in arbeiten zu müssen
while (isspace(*szTrunc)) ++szTrunc; // führende Whitespaces "abschneiden", danach zeigt der Pointer auf das erste Zeichen innerhalb szCpy das kein Whitespace ist
errno = 0; // der Integerwert errno wird durch strtol() mit der Konstante ERANGE befüllt, wenn der Bereich eines Long Integer überschritten wird
*pNum_out = strtol(szNum_in, &pchEnd, iBase_in); // die eigentliche C Funktion String zu Long Integer
if (ERANGE == errno) rgbitRet |= 4; // Zahl außerhalb Typbreite?
if // hier soll betrachtet werden, ob strtol() 0 zurückgibt, weil "0" gelesen wurde, oder weil kein numerischer String zu extrahieren war - Bsp.: "0$" OK, "$" nicht OK
(
*pNum_out == 0 // sollte strtol() etwas anderes als 0 zurückgeben, OK und der Rest braucht nicht betrachtet zu werden
&& ! // das ! beachten
(
szTrunc == 48 // wenn das erste Zeichen '0' ist, dann OK
|| // oder
(
(szTrunc == 43 || szTrunc == 45) // wenn das erste Zeichen '+' oder '-' ist ...
&& szTrunc[1] == 48 // ... und das zweite Zeichen '0', dann auch OK
)
)
) rgbitRet |= 4; // Ergo: Folgt nach ggf. abgeschnittenen führenden Whitespaces ein Teilstring, der nicht numerisch interpretiert werden konnte?
free(szCpy); // Speicher freigeben
if (*pchEnd) rgbitRet |= 2; // Abbruch nicht an Nullterminierung?
if (isspace(*szNum_in)) rgbitRet |= 1; // Whitespace am Stringanfang?
return rgbitRet; // 0 wenn OK, sonst Flags: 2^0 - Whitespaces am Stringanfang, 2^1 - Stringende nicht numerisch, 2^2 - nicht numerisch interpretierbar oder numerischer Stringteil außerhalb Typbreite, (2^3 - Fatal Error, siehe oben)
}
// wenn Fn_GetLong() eine Zahl von 1 bis 3 zurückgibt, war strtol() in der Lage einen Long Integer vom Stringanfang zu extrahieren
#define OK 0
#define ERR 4
int main(void)
{
char *szStr = NULL;
size_t cchLen = 0;
long lNum = 0;
unsigned rgbitFlags = -1, i = 0;
const char * const rgszErrMsg[4] = {"vorangestellte Whitespaces", "Abbruch vor Stringende", "nicht als Long Integer interpretiertbar", "Anwender-/Verarbeitungsfehler"};
const char * const rgszAckMsg[4] = {"keine vorangestellten Whitespaces", "Abbruch am Stringende", "als Long Integer interpretiertbar", "kein Anwender-/Verarbeitungsfehler"};
if (EXIT_SUCCESS == Fn_GetInput(&szStr, &cchLen)) // Benutzereingabe einholen und auf Verarbeitungsfehler prüfen.
{
printf("\nFn_GetInput:\n Laenge: %u\n String: %s\n", cchLen, szStr); // Anzeigen, was wir bekommen haben.
rgbitFlags = Fn_GetLong(szStr, 10, &lNum); // Versuch die Benutzereingabe als Long Integer zu interpretieren.
free(szStr); // Speicher (reserviert in Fn_GetInput()) freigeben, da szStr nicht länger benötigt wird!
// Beispiel, wie man auf die einzelnen Flags zugreifen könnte.
puts("\nFn_GetLong:\n Fehlerflags");
for (; i < 4; ++i)
{
if ((rgbitFlags >> i) & 1)
fprintf(stderr, " 1 - %s\n", rgszErrMsg[i]);
else
printf(" 0 - OK (%s)\n", rgszAckMsg[i]);
}
// Beispiel, wie man den Rückgabewert weiterhin interpretieren kann.
if (rgbitFlags == OK)
{
printf(" Gesamter String konnte als Long Integer interpretiert werden:\n %ld\n", lNum);
return EXIT_SUCCESS;
}
else if (rgbitFlags < ERR)
{
printf(" Long Integer wurde aus Teilstring extrahiert:\n %ld\n", lNum);
return EXIT_SUCCESS;
}
else
{
fprintf(stderr, " String/-anfang konnte nicht als Long Integer interpretiert werden.\n");
return EXIT_FAILURE;
}
}
fprintf(stderr, "Fn_GetInput: Verarbeitungsfehler.\n");
return EXIT_FAILURE;
}
Die Fn_GetLong gibt eine Bitmaske als unsigned int zurück, in der einzelne Fehlerflags gesetzt werden. Diese kannst du verarbeiten und später in deinem Programm selbst entscheiden welche Eingaben du als gültig akzeptierst.
Grüße
rubberman