2016-08-11 6 views
1

Das folgende ProgrammIst das Verhalten nicht definiert, wenn die Zielzeichenfolge in der Funktion strcat nicht null ist?

// Code has taken from http://ideone.com/AXClWb 
#include <stdio.h> 
#include <string.h> 

#define SIZE1 5 
#define SIZE2 10 
#define SIZE3 15 

int main(void){ 
    char a[SIZE1] = "Hello"; 
    char b[SIZE2] = " World"; 
    char res[SIZE3] = {0}; 

    for (int i=0 ; i<SIZE1 ; i++){ 
     res[i] = a[i]; 
    } 

    strcat(res, b); 
    printf("The new string is: %s\n",res); 
    return 0; 
} 

hat gut Verhalten definiert. Gemäß der Anforderung ist die Quellzeichenfolge b null-terminiert. Aber was wäre das Verhalten, wenn die Leitung

char res[SIZE3] = {0}; // Destination string 

mit

char res[SIZE3]; 

ersetzt Ist sagt Standard explizit über den Zielstring zu null zu beendet werden?

+2

Ich denke, 'strcat' beginnt die Suche nach dem' null Terminator' in die 'res' Zeichenkette vor der Verkettung der Zeichenfolge, so dass es UB ist. – LPs

+0

@LPs Was genau ist UB? Ist diese Zeile 'char res [SIZE3] = {0};' resize' auf '15' ZERO's zu initialisieren? – Michi

+0

@Michi Lesen Sie einen anderen Blick auf die Frage: OP möchte wissen, ob 'char res [SIZE3];' stattdessen. – LPs

Antwort

2

TL; DR Ja.


Da es sich um ein sprach Anwalt Frage, lassen Sie mich es meine zwei Cent hinzufügen.

C11 Zitiert, Kapitel §7.24.3.1/2 (EMPHAS ist Mine)

char *strcat(char * restrict s1,const char * restrict s2); 

Die strcat Funktion eine Kopie der Zeichenfolge anfügt, die von s2 zeigte (einschließlich der abschließenden Null Zeichen) bis zum Ende der Zeichenfolge, auf die s1 zeigt. Das Anfangszeichen von s2 überschreibt das Nullzeichen am Ende von s1. [...

]

und per definitionem ein Zeichenfolgeist nullterminierte, §7.1.1/1

A zitiert Zeichenfolge eine zusammenhängende Sequenz von Zeichen beendet durch und einschließlich der ersten null Zeichen.

Also, wenn die Quelle char Array nicht null-terminierte (d.h. nicht eine Zeichenfolge), strcat() sehr weit über die Grenzen auf der Suche nach das Ende die undefined behavior aufruft gehen kann.

Gemäß Ihrer Frage, char res[SIZE3]; ist eine automatische lokale Variable, wird unbestimmter Wert enthalten, und wenn als Ziel von strcat() verwendet, wird UB aufrufen.

+0

Sie sagen also, dass hacks Code UB ist? – Michi

+0

@Michi Ja, richtig. –

+0

Was bedeutet diese Zeile 'char res [SIZE3] = {0};'? – Michi

2

Wenn Sie res verlassen uninitialized dann, nach dem Kopieren a in res (in for-Schleife), gibt es keinen Terminator NUL in res. Das Verhalten von strcat() ist daher nicht definiert, wenn die Zielzeichenfolge kein NUL-Byte enthält.

Grundsätzlich erfordert strcat() beiden seiner Argumente strings sein (d.h. beide muss der Abschluss NUL Byte enthalten). Ansonsten ist es undefined behaviour. Diese ist offensichtlich aus der Beschreibung von strcat():

§7.23.3.2, strcat() function

Die strcat Funktion anhängt eine Kopie der Zeichenfolge von s2 wies (einschließlich des abschließenden Nullzeichen) an das Ende des String wies auf s1. Das Anfangszeichen von s2 überschreibt das Nullzeichen am Ende von s1.

(Schwerpunkt meins).

+0

'a' wird nicht in' res' kopiert, es ist 'b' und es ist null terminiert. – haccks

+0

Ich habe über das Kopieren in der for-Schleife gesprochen, wo 5 Bytes in 'res' kopiert werden, ohne den NUL-Terminator. Folglich führt das nachfolgende 'strcat()' zu UB. –

3

Ich denke manausdrücklich sagt dass

Beschreibung

Die strcat() gibt die src Zeichenfolge an den dest Zeichenfolge anhängt, das abschließende Null-Byte-Überschreiben ('\ 0') an Das Ende des Ziels, und fügt dann ein abschließendes Nullbyte hinzu. Die Zeichenfolgen dürfen sich nicht überschneiden, und die Zielzeichenfolge muss genügend Platz für das Ergebnis haben. Wenn dest nicht groß genug ist, ist das Programmverhalten nicht vorhersehbar; Pufferüberläufe sind ein beliebter Weg, um sichere Programme anzugreifen.

Enphasis Mine

BTW denke ich strcat beginnt für die null terminator in die Zeichenkette dest suchen, bevor die neue Zeichenfolge verketten, so dass es UB ist offensichtlich, soweit dest String mit dynamischem Speicher hat.

Im vorgeschlagenen Code

for (int i=0 ; i<SIZE1 ; i++){ 
    res[i] = a[i]; 
} 

Kopieren 5 Zeichen von a und nicht das Nullabschluss zu res String, so dass andere Bytes 5-14 sind nicht initialisiert.

Norm sagt auch über safaer Implementierung strcat-s

K.3.7.2.1 Die strcat_s Funktion

Synopsis

#define _ _STDC_WANT_LIB_EXT1_ _ 1 
     #include <string.h> 
     errno_t strcat_s(char * restrict s1, 
      rsize_t s1max, 
      const char * restrict s2); 

Runtime-Einschränkungen

2 Le t m bezeichnen den Wert s1max - strnlen_s (s1, s1max) beim Eintritt in strcat_s.

Wir können sehen, dass strlen_s immer sie gültige Größe für den dest Puffer zurück. Aus meiner Sicht wurde diese Implementierung eingeführt, um das UB der Frage zu vermeiden.

+0

'also andere Bytes von 5 bis 14 sind nicht initialisiert. Was bedeutet diese Zeile 'char res [SIZE3] = {0};'? – Michi

+0

@Michi Es wird auf die Frage, die sagt: _wenn ich 'char res [SIZE3]; statt_? – LPs

+1

Ich war auf den CODE selbst konzentrieren :)) – Michi

1

Wenn char res[SIZE3]; auf dem Stack ist, wird es zufällige/undefined Sachen drin haben.
Sie werden nie wissen, ob es ein Null-Byte innerhalb res[SIZE3] gibt, also ja, strcat ting zu undefiniert ist.

Wenn char res[SIZE3]; ist ein nicht initialisierte globale, es sein werden alle Nullen, die sie als leer Cschnur verhalten machen und strcat es ing werden sicher sein (solange size3 ist groß genug für das, was Sie anhängen).

Verwandte Themen