Forum: PC-Programmierung C Einführung: strncpy


von Gerd (Gast)


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. :(
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
5
int main()
6
{
7
    char myString[] = "My Name is Gerd"; // Length is 16, Size is 16+Null terminator
8
9
    char tempName[10];
10
    char tempName2[10];
11
12
    strncpy(tempName,myString,sizeof(tempName)-1);
13
    strncpy(tempName2,myString,sizeof(tempName2)-1);
14
    printf("myString: %s\ntempName: %s\ntempName2: %s\n",myString,tempName,tempName2);
15
    printf("myString: strlen= %d, sizeof= %d\n",strlen(myString),sizeof(myString));
16
    printf("tempName: strlen= %d, sizeof= %d\n", strlen(tempName),sizeof(tempName));
17
    printf("tempName2: strlen= %d, sizeof= %d\n", strlen(tempName2),sizeof(tempName2));
18
19
20
    return 0;
21
}

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)


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)


Lesenswert?

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

(oder mit memset(...))

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

von foobar (Gast)


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)


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)


Lesenswert?


von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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

Alternativ kann man die Ziele auch nach strncpy() sicherheitshalber 
terminieren:
1
    strncpy(tempName,myString,sizeof(tempName)-1);
2
    strncpy(tempName2,myString,sizeof(tempName2)-1);
3
    tempName[sizeof(tempName)-1] = '\0';
4
    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


Lesenswert?


von Gerd (Gast)


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)


Lesenswert?

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

Es hat Klick gemacht - glaube ich :)

Danke und Gruß,

von fop (Gast)


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)


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)


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)


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)


Lesenswert?

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

Das wurde weiter oben schon beantwortet.

leo

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.