Forum: PC-Programmierung C Einführung: strncpy


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Gerd (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi

Ich bringe mir gerade C bei, über einen Udemy Kurs. Momentan behandeln 
wir Strings, speziell strncpy. Jetzt habe ich ein kleines Programm 
geschrieben, dessen Ergebnis ich nicht ganz nachvollziehen kann. Was 
genau geschieht bei tempName2, so dass der Inhalt ein anderer ist als 
bei tempName? strlen von tempName is ebenfalls 19 und nicht 9? Meine 
Vermutung ist, dass ich strncpy falsch anwende oder ein wichtiges Detail 
unterschlage. :(
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char myString[] = "My Name is Gerd"; // Length is 16, Size is 16+Null terminator

    char tempName[10];
    char tempName2[10];

    strncpy(tempName,myString,sizeof(tempName)-1);
    strncpy(tempName2,myString,sizeof(tempName2)-1);
    printf("myString: %s\ntempName: %s\ntempName2: %s\n",myString,tempName,tempName2);
    printf("myString: strlen= %d, sizeof= %d\n",strlen(myString),sizeof(myString));
    printf("tempName: strlen= %d, sizeof= %d\n", strlen(tempName),sizeof(tempName));
    printf("tempName2: strlen= %d, sizeof= %d\n", strlen(tempName2),sizeof(tempName2));


    return 0;
}


Output:
myString: My Name is Gerd
tempName: My Name i
tempName2: My Name iMy Name i
myString: strlen= 15, sizeof= 16
tempName: strlen= 9, sizeof= 10
tempName2: strlen= 19, sizeof= 10

Process returned 0 (0x0)   execution time : 0.029 s
Press any key to continue.

Danke und Gruß,

von leo (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Gerd schrieb:
> Ich bringe mir gerade C bei, über einen Udemy Kurs. Momentan behandeln
> wir Strings, speziell strncpy.

Du solltest wohl zuerst die Manuals lesen. Da steht u.a.

"Warning: If there is no null byte
       among the first n bytes of src, the string placed in dest will 
not be null-terminated.
"

https://www.manpagez.com/man/3/strncpy/

leo

von zitter_ned_aso (Gast)


Bewertung
0 lesenswert
nicht lesenswert
weil du die beiden char-Arrays nicht initialisiert hast. Bei dir kann da 
jetzt alles mögliche drin sein.
char tempName[10]={0};                                              
char tempName2[10]={0}; 

(oder mit memset(...))

oder später String mit '\0' abschließen.

von foobar (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Einen Tipp an Anfänger: vergiss einfach, dass es strncpy gibt[1].  Die 
ist für eine spezielle Andwendung entworfen worden (Festweitendatensätze 
füllen, z.B. Lochkarten) und nur aus Versehen in die String-Library 
gerutscht ;-)  Durch die (für andere Anwendung) zusätzliche nötige 
Drumrumprogrammiererei geht ihr Nutzen gegen Null.


[1] strtok auch

von Hmmm (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Gerd schrieb:
> tempName2: My Name iMy Name i

Weil tempName2 das \0 fehlt (siehe Antwort von leo), wird einfach bei 
tempName (liegt weiter oben auf dem Stack) weitergelesen.

von foobar (Gast)


Bewertung
0 lesenswert
nicht lesenswert

von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
zitter_ned_aso schrieb:
> weil du die beiden char-Arrays nicht initialisiert hast.

Alternativ kann man die Ziele auch nach strncpy() sicherheitshalber 
terminieren:
    strncpy(tempName,myString,sizeof(tempName)-1);
    strncpy(tempName2,myString,sizeof(tempName2)-1);
    tempName[sizeof(tempName)-1] = '\0';
    tempName2[sizeof(tempName2)-1] = '\0';

Vorteil: Es muss nur noch jeweils ein Byte geschrieben werden, um die 
Strings sicher zu terminieren.

Eine vorsorgliche Initialisierung, wie Du sie vorschlägst, füllt das 
Array komplett, wovon viele Bytes durch das nachfolgende strncpy() dann 
nochmals überschrieben werden.

von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert

von Gerd (Gast)


Bewertung
0 lesenswert
nicht lesenswert
leo schrieb:
> Du solltest wohl zuerst die Manuals lesen. Da steht u.a.

Hallo leo

habe ich bereits gelesen.

Frage:
Warum funktioniert das bei tempName, aber nicht bei tempName2? Der Code 
für tempName und tempName2 ist identisch, oder übersehe ich da etwas?

Gruß,

von Gerd (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ups, entschuldig bitte meinen vorigen Beitrag. Der sollte nicht 
abgesendet werden.

Es hat Klick gemacht - glaube ich :)

Danke und Gruß,

von fop (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
foobar schrieb:
> Einen Tipp an Anfänger: vergiss einfach, dass es strncpy gibt[1].  Die
> ist für eine spezielle Andwendung entworfen worden (Festweitendatensätze
> füllen, z.B. Lochkarten) und nur aus Versehen in die String-Library
> gerutscht ;-)  Durch die (für andere Anwendung) zusätzliche nötige
> Drumrumprogrammiererei geht ihr Nutzen gegen Null.

Ja, vergesst, dass es Buffer Overflows gibt und schreibt weiterhin 
Murks-Software mit Sicherheitslücken. Man muss den Geheimdiensten ja 
auch eine Chance lassen.
Das hier beschriebene Verhalten entsteht ja dadurch, dass der 
Nullterminator fehlt. Und Du willst jetzt alles bis zum Nullterminator 
in einen Puffer quetschen ? Der ist im Zweifelsfall zu klein, und Du 
überschreibst irgendwas, das dahinter steht. Es gibt auch genug Leute, 
die Dir Deine Eingangsdaten so zu manipulieren versuchen, dass genau 
dieser Fall eintritt.

von Carl D. (jcw2)


Bewertung
1 lesenswert
nicht lesenswert
fop schrieb:
> foobar schrieb:
>> Einen Tipp an Anfänger: vergiss einfach, dass es strncpy gibt[1].  Die
>> ist für eine spezielle Andwendung entworfen worden (Festweitendatensätze
>> füllen, z.B. Lochkarten) und nur aus Versehen in die String-Library
>> gerutscht ;-)  Durch die (für andere Anwendung) zusätzliche nötige
>> Drumrumprogrammiererei geht ihr Nutzen gegen Null.
>
> Ja, vergesst, dass es Buffer Overflows gibt und schreibt weiterhin
> Murks-Software mit Sicherheitslücken. Man muss den Geheimdiensten ja
> auch eine Chance lassen.
> Das hier beschriebene Verhalten entsteht ja dadurch, dass der
> Nullterminator fehlt. Und Du willst jetzt alles bis zum Nullterminator
> in einen Puffer quetschen ? Der ist im Zweifelsfall zu klein, und Du
> überschreibst irgendwas, das dahinter steht. Es gibt auch genug Leute,
> die Dir Deine Eingangsdaten so zu manipulieren versuchen, dass genau
> dieser Fall eintritt.

"Du wolltest schon immer coole C++-Programme schreiben?"
Dann geh zu dem Typ, der aussieht, als wären nicht all seine 
Nahrungsergänzungsmittel legal erwerbbar.

von foobar (Gast)


Bewertung
2 lesenswert
nicht lesenswert
> Ja, vergesst, dass es Buffer Overflows gibt und schreibt weiterhin
> Murks-Software mit Sicherheitslücken.

Mein Tipp ging eher in die Richtung, dass die Benutzung von strncpy 
gerade nicht das adäquate Mittel ist!  Ob ich statt strcpy strncpy 
benutze, hilft exakt gar nichts.  Statt bei strcpy wild im Speicher zu 
schreiben, wird bei strncpy wild im Speicher gelesen (der spätere 
Nutzer) und leakt evtl direkt Daten.  Silent truncation ist eh der 
falsche Ansatz (ist schon genug drüber geschrieben worden) - eine 
explizite Prüfung mit passender Behandlung ist der korrekte Weg.  Wer 
glaubt, dass er mit den "n"-Funktionen was für die Sicherheit tut, ist 
auf dem Holzweg.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
fop schrieb:
> foobar schrieb:
>> Einen Tipp an Anfänger: vergiss einfach, dass es strncpy gibt[1].
> Ja, vergesst, dass es Buffer Overflows gibt und schreibt weiterhin
> Murks-Software mit Sicherheitslücken. Man muss den Geheimdiensten ja
> auch eine Chance lassen.

strncpy ist broken by design. Wenn der Zielpuffer größer ist als der 
Quellstring mit Nullterminator, werden unnötig viele Nullen geschrieben. 
Wenn er dagegen kleiner ist als der Quellstring, wird die eine Null, die 
zwingend erforderlich ist, einfach weggelassen. Man muss die Funktion 
also so verwenden, dass man als Zielgröße ein Byte weniger als die Größe 
des Ziels angibt und von Hand eine Null in das letzte Byte schreibt.

> Das hier beschriebene Verhalten entsteht ja dadurch, dass der
> Nullterminator fehlt.

… und zwar weil strncpy in dem Glauben verwendet wurde, dass es sowas 
nicht macht. Ich möchte gar nicht wissen, wie viele Sicherheitslücken 
genau deshalb so rumgeistern.
strncpy ist hier nicht die Lösung, sondern das Problem.

> Und Du willst jetzt alles bis zum Nullterminator in einen Puffer quetschen?

Er will vermutlich nur eine besser geeignete Funktion als strncpy 
verwenden. Bei manchen Compilern gibt es eine Funktion strlcpy, die 
nicht Standard ist, aber dafür das tut, was man eigentlich von ihr 
erwartet.

: Bearbeitet durch User
von leo (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Gerd schrieb:
> Frage:
> Warum funktioniert das bei tempName, aber nicht bei tempName2

Das wurde weiter oben schon beantwortet.

leo

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.