Konkatinierung von char* - gängige Praxis



  • Zufall schrieb:

    In main() könnten ebenfalls malloc() und das (fehlende) zugehörige free() entfallen, wenn ein Buffer in der geeigneten Größe für die max. mögliche Pfad-/Dateilänge vorgehalten würde.

    Das entbindet dich allerdings nicht von der Pflicht zur Prüfung, ob die beiden Teilstrings inkl. Nullterminierung tatsächlich in diesen Buffer passen.



  • pointerbub schrieb:

    ich bin sehr erfahren in C

    Wow.
    Zeugt vom gesundem Selbstbewusstsein, näher betrachtet aber eher eine naive Sicht der Dinge bzw. eine pubertäre Provokation um professionelle Antworten zu bekommen.

    - nur Deppen benutzen strncpy
    - es ist nicht sichergestellt, dass argv[0] den Programmnamen enthält
    - '/' als Verzeichnisseparator ist ebenfalls nicht garantiert
    - malloc casten nur Deppen
    - free vergessen
    - in C werden nirgendwo Arrays 'automatisch kopiert'

    char *replacefilename(const char **argv,char *s)
    {
    	char *p = strrchr(*argv,'/');
    	if(!p) p = strrchr(*argv,'\\');
    	if(!p) return 0;
    	*s=0;
    	strncat(s,*argv,p-*argv+1);
    	return strcat(s,argv[1]);
    }
    
    int main(void) {
    	const char *a[]={"/foo/bar","baz"}; void*p;
    	puts(replacefilename(a,p=malloc(1+strlen(a[0])+strlen(a[1]))));
    	free(p);
    	return 0;
    }
    

    http://ideone.com/F3PyM5



  • Wutz schrieb:

    pointerbub schrieb:

    ich bin sehr erfahren in C

    Wow.
    Zeugt vom gesundem Selbstbewusstsein, näher betrachtet aber eher eine naive Sicht der Dinge bzw. eine pubertäre Provokation um professionelle Antworten zu bekommen.

    bla bla. Da fehlt ein "nicht".

    Zufall schrieb:

    pointerbub schrieb:

    Es tut, was ich will, ...

    Das ist rein zufällig, denn deine mit malloc() erzeugten Buffer sind in beiden Fällen zu klein.

    Du meinst, weil ich das '\0' nicht berücksichtige? Ok, das sollte ich ändern.

    Zufall schrieb:

    In main() könnten ebenfalls malloc() und das (fehlende) zugehörige free() entfallen, wenn ein Buffer in der geeigneten Größe für die max. mögliche Pfad-/Dateilänge vorgehalten würde.

    Warum? Das würde bedeuten, dass ich statisch eine Arraygröße vorgeben muss, obwohl ich nicht weiß, wie groß die Daten wirklich sein werden. Ich möchte einen Buffer Overflow verhindern, will aber auch nicht mehr Daten reservieren als nötig.

    [quote="Wutz"]

    pointerbub schrieb:

    - nur Deppen benutzen strncpy

    Begründung? Deppen nutzen strcpy.

    [quote="Wutz"]

    pointerbub schrieb:

    - es ist nicht sichergestellt, dass argv[0] den Programmnamen enthält

    Wann ist das nicht der Fall?

    [quote="Wutz"]

    pointerbub schrieb:

    - malloc casten nur Deppen

    Begründung? Wie allokiert Du denn dynamisch Speicher? Castet Du später void Pointer?



  • pointerbub schrieb:

    Wutz schrieb:

    - malloc casten nur Deppen

    Begründung? Wie allokiert Du denn dynamisch Speicher? Castet Du später void Pointer?

    void* ist implizit in jeden anderen Zeiger-Typ konvertierbar. Der Cast ist also unnötig. Wenn Dein Compiler ohne den Cast nicht kompilieren will, ist er kaputt.



  • pointerbub schrieb:

    Wutz schrieb:

    - nur Deppen benutzen strncpy

    Begründung? Deppen nutzen strcpy.

    Stop using strncpy already!

    pointerbub schrieb:

    Wutz schrieb:

    - es ist nicht sichergestellt, dass argv[0] den Programmnamen enthält

    Wann ist das nicht der Fall?

    Immer dann, wenns dem Host Environment anders einfällt. Garantiert? Nie. Geh Standard lesen.


  • Mod

    Swordfish schrieb:

    pointerbub schrieb:

    Wutz schrieb:

    - es ist nicht sichergestellt, dass argv[0] den Programmnamen enthält

    Wann ist das nicht der Fall?

    Immer dann, wenns dem Host Environment anders einfällt. Garantiert? Nie. Geh Standard lesen.

    Wobei es schon ziemlich spitzfindig ist zu sagen, dass da nicht zuverlässig der Programmaufruf stünde. Ob man für Windows, Linux, Mac oder sonst ein Betriebssystem mit > 0.1 Promille Marktanteil programmiert weiß man schließlich in der Regel. Und dann ist dieses Verhalten auch garantiert. Der eigentliche Knackpunkt ist, dass ich oben nicht ohne Grund "Programmaufruf" geschrieben habe. Der Threadersteller geht aber davon aus, dass da garantiert der Name der Executable mit vollem Pfad stünde. Dies ist definitiv nicht garantiert. Einfache Gegenbeispiele sind Verknüpfungen oder Aliase. Denn in argv[0] steht wirklich der Bezeichner über den das Programm gestartet wurde, dieser ist aber nicht unbedingt der Dateiname¹ der Executable.

    ¹: Es ist auch nicht unbedingt gegeben, dass eine Executable überhaupt einen eindeutigen Dateinamen haben muss (Hardlinks...) oder ob es überhaupt eine Executable-Datei gibt (Builtins...).



  • Swordfish schrieb:

    Stop using strncpy already!

    Das funktioniert aber nur in C++.



  • SG1 schrieb:

    void* ist implizit in jeden anderen Zeiger-Typ konvertierbar. Der Cast ist also unnötig. Wenn Dein Compiler ohne den Cast nicht kompilieren will, ist er kaputt.

    Das wusste ich nicht. Danke für den Hinweis.

    Swordfish schrieb:

    Stop using strncpy already!

    Sehr interessanter Artikel. Dass strcpy anfällig gegenüber Buffer-Overflows ist, war mir klar. Daher habe ich auf das "n" im Namen geachtet. Dass diese Funktionen aber keine Nullterminierung garantieren, war mir nicht klar und mir leuchtet die potenzielle Gefahr ein. Die vorgeschlagene Lösung kommt für mich nicht partiell infrage, weil ich, wie SG1 richtig festgestellt habe, nicht C++ programmiere, sondern ausschließlich C. Vermutlich bleibt mir nicht anderes übrig, als die Funktion selbst zu implementieren.



  • Kann mir jemand sagen, warum im Code von Wutz

    p-*arg+1
    

    16 ergibt? p ist der Pointer auf die Stelle, an der das letzte / steht. *arg ist der erste const char* in a. Wie funktioniert die Zeigerarithmetik hier?



  • *argv zeigt auf den programmpfad, p auf den gefundenen pfadseparator, somit ist p - *argv die distanz der beiden, die anzahl der zeichen bis zum pfadseparator. Damit dieser eingeschlossen wird, noch eins dazuaddiert.



  • pointerbub schrieb:

    Die vorgeschlagene Lösung kommt für mich nicht partiell infrage, weil ich, wie SG1 richtig festgestellt habe, nicht C++ programmiere, sondern ausschließlich C.

    Ich verstehe in diesem Satz das Wort "partiell" nicht. Was sagt es aus?



  • volkard schrieb:

    pointerbub schrieb:

    Die vorgeschlagene Lösung kommt für mich nicht partiell infrage, weil ich, wie SG1 richtig festgestellt habe, nicht C++ programmiere, sondern ausschließlich C.

    Ich verstehe in diesem Satz das Wort "partiell" nicht. Was sagt es aus?

    Das "nicht" ist dieses Mal zu viel ;). Partiell bedeutet teilweise. Der Artikel behauptet nämlich, man solle die entsprechende Codevariante selbst programmieren. Dieser Teil trifft auf mich zu. Jedoch kommt dafür C++ zum Einstz. Dies trifft bei mir nicht zu.

    Techel schrieb:

    *argv zeigt auf den programmpfad, p auf den gefundenen pfadseparator, somit ist p - *argv die distanz der beiden, die anzahl der zeichen bis zum pfadseparator. Damit dieser eingeschlossen wird, noch eins dazuaddiert.

    Danke, das habe ich verstanden. Jedoch ist mir nicht klar, warum die Differenz der Pointer die Anzahl der Zeichen bis zum Pfadseperator angibt. Anscheinend habe ich da noch Defizite im Verständnis der Zeigerarithmetik. Ich subtrahiere ja Adressen von einander. Warum erhalte ich dennnoch das gewünschte Ergebnis?



  • Ah, ich verstehe vermutlich. Diese Art der Rechnung funktioniert nur, weil die Daten hintereinander im Speicher liegt. Ist das richtig?



  • Genau.



  • pointerbub schrieb:

    Das "nicht" ist dieses Mal zu viel ;).

    Deine Postings sind sehr fein zu lesen. Du gibst Dir absolut genug Mühe als Fragesteller.



  • SG1 schrieb:

    Swordfish schrieb:

    Stop using strncpy already!

    Das funktioniert aber nur in C++.

    Eben. Ich bin kein C Programmierer und in C++ brauche ich das normalerweise nicht. Die Probleme von strcpy und strncpy kannte ich aber natürlich schon. Und was ist nun die bevorzugte C Lösung?



  • - strncat mit der Vorbedingung dass ein Leerstring vorliegt (wie im Beispiel oben)
    - sprintf mit precision: sprintf(s,"%.*s",3,"blafasel")

    wobei in beiden Fällen natürlich der Zielspeicher ausreichend groß dimensioniert sein muss, was einem die beiden Varianten NICHT abnehmen.
    Beides geht schon ab C89, garantiert die String-Terminierung und schneidet im Bedarfsfall den Quellstring ab.



  • volkard schrieb:

    pointerbub schrieb:

    Das "nicht" ist dieses Mal zu viel ;).

    Deine Postings sind sehr fein zu lesen. Du gibst Dir absolut genug Mühe als Fragesteller.

    Du hast ja auch die Möglichkeit, deinen einen Satz zweimal nachzukorrigieren. Das ist einem Unregistrierten leider nicht möglich.



  • Dir wird dieses Privileg auch gegönnt sein, für nur 15€ pro Monat für die Mitgliedschaft im C++-Forum.


Anmelden zum Antworten