2017-03-07 5 views
0

Mein Programm muss feststellen, ob ein Zeiger s1 irgendwelche Zeichen von s2 enthält und dann einen Zeiger auf diese Position in s1 zurückgibt, andernfalls gebe NULL zurück.Probleme beim Verständnis dieses Const-Zeigerfehlers

#include <stdio.h> 

char * strpbrk(const char *, const char *); 

int main(void){ 
const char *s1 = "hello"; 
const char *s2 = "world"; 

printf("Repeated character in s1 is %p", *strpbrk(s1, s2)); 

} 

char * strpbrk(const char * s1, const char * s2){ 
char *p1, *p2; 

p1 = s1; 
p2 = s2; 
for(; *p1 != '\0'; p1++){ 
    for(; *p2 != '\0'; p2++){ 
     if(*p1 == *p2){ 
      break; 
     } 
     else{ 
      return '\0'; 
     } 
    } 
} 
return p1; 
} 

Halten Sie diesen Fehler:

test.c: In function ‘strpbrk’: 
test.c:16:5: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] 
    p1 = s1; 
    ^
test.c:17:5: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] 
    p2 = s2; 
+5

Es ist wichtig zu wissen, dass dies kein Fehler ist, dann ist es eine Warnung - die von denen zwei ganz verschieden sind. Der Grund für die Warnung ist, dass Sie 'p1' und' p2' als 'char' deklariert haben, im Gegensatz zu' const char'. –

+0

Ich sehe Warnungen, keine Fehler. –

+1

Ich denke, die Nachricht ist offensichtlich. Sie haben auf der einen Seite einen konstanten und auf der anderen Seite eine nicht konstante. Du wirfst den Qualifier ab. – StoryTeller

Antwort

0

Der beste Weg, der Compiler-Warnung loszuwerden, ist p1 und p2 auf Zeiger auf const char zu ändern und dann eine Guss hinzufügen, wenn Sie p1 zurückzukehren. Auf diese Weise sehen Leser des Codes, dass Sie die String-Argumente nicht ändern wollen.

Es gab auch ein paar Fehler in der Implementierung, die ich (hoffentlich) ausgebügelt habe.

char * strpbrk(const char * s1, const char * s2) { 
    const char *p1, *p2; 

    for (p1 = s1; *p1 != '\0'; p1++) { // out is a label 
     for (p2 = s2; *p2 != '\0'; p2++) { 
      if (*p1 == *p2) { 
       // Match found 
       return (char*)p1; 
      } 
     } 
    } 
    // No match found 
    return NULL; 
} 
+0

Es gibt keine solche Syntax wie 'Breakout;'. – aschepler

+0

@ascheppler Das ist, was ich seit über 15 Jahren von der Programmierung von Java bekomme. Danke, dass du darauf hingewiesen hast. Code geändert. –

+0

Ich glaube, dass der Cast schlecht spezifiziertes Verhalten nach 6.7.6.1 aufruft. Die Zeigertypen sind nicht kompatibel. Du solltest keine Qualifier wegwerfen. – Lundin

0

Dies ist ein Widerspruch in mehrere der Standard-Bibliotheksfunktionen, strpbrk, strstr usw. Der Standard verlangt, dass sie einen nicht konstanten Zeiger auf das gefundene Element in einem const qualifizierten String zurück. Was das Standardkomitee rauchte, als sie sich entschieden, den Parametern dieser Bibliotheksfunktionen die Konst-Korrektheit hinzuzufügen, aber nicht den Rückgabetypen, weiß ich nicht.

Es gibt keine Möglichkeit, eine solche Funktion im Standard C zuverlässig zu implementieren, da es nicht erlaubt ist, von einem "qualifizierten Zeiger in einen Typ" in einen "Zeiger vom Typ" zu konvertieren. C11 6.7.6.1:

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

Deshalb erhalten Sie immer Compiler-Warnungen. Die Verletzung dieser Regel wird als nicht definiertes Verhalten durch die (nicht-normativ) Anhang J aufgeführt:

Two pointer types that are required to be compatible are not identically qualified, or are not pointers to compatible types (6.7.6.1).

So ist die Antwort auf Ihre Frage ist, dass Funktionen wie strpbrk und strstr nicht sicher in Standard C und portabel erhalten implementiert können Sie werden müssen entweder mit nicht-standardmäßigen Spracherweiterungen oder einer anderen Programmiersprache implementiert werden.

Die solide Lösung besteht darin, die Deklaration der Funktion zu ignorieren, die vom Standard vorgegeben wird, und stattdessen eine rationale Deklaration zu verwenden. Entweder

char* strpbrk_rw (char* s1, const char* s2); // read/write parameter 

oder

const char* strpbrk_ro (const char* s1, const char* s2); // read-only parameter 
Verwandte Themen