2010-01-15 11 views
19

Pochodzę z tła Java Uczę się C, ale uważam, że te niejasne komunikaty o błędach kompilatora coraz bardziej frustrują. Oto mój kod:Przypis tworzy wskaźnik z liczby całkowitej bez rzutowania

/* 
* PURPOSE 
*  Do case-insensetive string comparison. 
*/ 
#include <stdio.h> 
#include <string.h> 
#include <ctype.h> 

int compareString(char cString1[], char cString2[]); 
char strToLower(char cString[]); 

int main() { 
    // Declarations 
    char cString1[50], cString2[50]; 
    int isEqual; 

    // Input 
    puts("Enter string 1: "); 
    gets(cString1); 
    puts("Enter string 2: "); 
    gets(cString2); 

    // Call 
    isEqual = compareString(cString1, cString2); 
    if (isEqual == 0) 
     printf("Equal!\n"); 
    else 
     printf("Not equal!\n"); 

    return 0; 
} 

// WATCH OUT 
//  This method *will* modify its input arrays. 
int compareString(char cString1[], char cString2[]) { 
    // To lowercase 
    cString1 = strToLower(cString1); 
    cString2 = strToLower(cString2); 

    // Do regular strcmp 
    return strcmp(cString1, cString2); 
} 

// WATCH OUT 
//  This method *will* modify its input arrays. 
char strToLower(char cString[]) { 
    // Declarations 
    int iTeller; 

    for (iTeller = 0; cString[iTeller] != '\0'; iTeller++) 
     cString[iTeller] = (char)tolower(cString[iTeller]); 

    return cString; 
} 

Generuje dwa ostrzeżenia.

  • umożliwia przypisanie wskaźnika od liczby całkowitej bez obsady
    • cString1 = strtolower (cString1);
    • cString2 = strToLower (cString2);
  • powrót sprawia całkowitą od wskaźnika bez oddanych
    • powrót cstring;

Czy ktoś może wyjaśnić te ostrzeżenia?

Odpowiedz

36

Struny C nie są niczym struny Java. Zasadniczo są to tablice postaci.

Otrzymujesz błąd, ponieważ strToLower zwraca znak. Znak jest formą liczby całkowitej w C. Przypisujesz ją do char [], która jest wskaźnikiem. Stąd "konwersja liczby całkowitej do wskaźnika".

Twoja maszyna strToLower wprowadza wszystkie swoje zmiany na swoim miejscu, nie ma powodu, aby zwracała cokolwiek, a zwłaszcza char. Powinieneś "zwrócić" pustkę lub znak *.

Przy wywołaniu funkcji strToLower nie ma potrzeby przypisania, w zasadzie po prostu przekazujesz adres pamięci dla cString1.

Z mojego doświadczenia wynika, że ​​napisy w C są najtrudniejszą rzeczą do nauczenia się dla każdego, kto pochodzi z Java/C# z powrotem do C. Ludzie mogą sobie poradzić z przydzielaniem pamięci (ponieważ nawet w Javie często przydzielacie tablice). Jeśli twoim ostatecznym celem jest C++, a nie C, możesz wolę mniej skupiać się na ciągach C, upewnij się, że rozumiesz podstawy i po prostu użyj ciągów C++ ze STL.

+0

(+1) ta wartość dodaje autopulowanej odpowiedzi –

+0

To jednak nie ** bezpośrednio ** dotyczy tematu pytania - jest to rozwiązanie pośrednie: D, aby wyeliminować ostrzeżenie kompilatora, odpowiedź auto jest bardziej trafna: D –

+0

Ok, wyjaśniono tu odpowiedź. – Uri

4

strtolower typ zwrotny powinien być char* nie char (lub powinien on w ogóle nic nie wrócić, ponieważ nie ponownie przydzielić łańcuch)

+0

(+1, prawie -1 = D) To, co chcesz powiedzieć, to zmienić typ zwracany ..... to zwraca char *, jednak jest to sprzeczne z typem zwracania ... –

+0

Naprawiono. Dzięki, nie bardzo to zrozumiałem :) – James

1
  • 1) Nie stosować gets! Wprowadzasz lukę w zabezpieczeniach polegającą na przepełnieniu bufora. Zamiast tego użyj fgets(..., stdin).

  • 2) W strToLower powracasz char zamiast z char -array. Albo zwróć char* jako autopulated zasugerował, albo po prostu zwróć void, ponieważ i tak modyfikujesz dane wejściowe.W rezultacie, po prostu napisz

 

strToLower(cString1); 
strToLower(cString2); 
  • 3) Aby porównać case-niewrażliwy sznurki, można użyć strcasecmp (Linux & Mac) lub stricmp (Windows).
0

Nie trzeba te dwa assigments:

cString1 = strToLower(cString1); 
cString2 = strToLower(cString2); 

modyfikujesz sznurki w miejscu.

ostrzeżenia są ponieważ wraca karbonizat i przypisanie char [] (co jest równoważne char *)

-1
char cString1[] 

to tablica, czyli wskaźnik na pierwszy element szeregu elementów tego samego typu danych. Zauważ, że nie przekazujesz tablicy wartości by-u, ale przez-wskaźnik.

char strToLower(...) 

Jednak zwraca char. Więc przypisanie

cString1 = strToLower(cString1); 

posiada różne typy na każdej stronie operatora przypisania .. jesteś rzeczywiście przypisanie „char” (sort of Integer) do tablicy, która postanawia prostego wskaźnika. Ze względu na niejawne reguły konwersji C++ to działa, ale wynik to śmieci i dalszy dostęp do tablicy powoduje niezdefiniowane zachowanie.

Rozwiązaniem jest sprawienie, aby strToLower powrócił char*.

0

Zwracasz char, a nie char *, który jest wskaźnikiem do pierwszego znaku tablicy.

Jeśli chcesz zwrócić nową tablicę znaków zamiast modyfikować w miejscu, możesz poprosić o już przydzielony wskaźnik (char *) jako parametr lub niezainicjowany wskaźnik. W tym ostatnim przypadku musisz przydzielić odpowiednią liczbę znaków dla nowego ciągu i pamiętaj, że w parametrach C przekazanych przez wartość ZAWSZE, więc musisz użyć char ** jako parametru w przypadku tablicy przydzielonej wewnętrznie przez funkcję. Oczywiście, wywołujący musi później zwolnić wskaźnik.

0

strToLower powinien zwrócić znak * zamiast znaku. Coś takiego mogłoby zrobić.

char *strToLower(char *cString) 
2

jak inni już wspomniano, w jednym przypadku, gdy starają się powrócić cString (która jest wartością char * w tym kontekście - wskaźnik) z funkcji, która została zgłoszona do powrotu char (co jest liczbą całkowitą) . W innym przypadku wykonaj odwrotność: przypisujesz wartość zwracaną char do wskaźnika char *. To właśnie uruchamia ostrzeżenia. Z pewnością musisz zadeklarować swoje wartości zwracane jako char *, a nie jako char.

Uwaga BTW, że te przypisania są w rzeczywistości naruszeniami wiązań z punktu widzenia języka (tj.są "błędami"), ponieważ mieszanie wskaźników i liczb całkowitych w C jest nielegalne (poza całkowitym stałym zerem). Twój kompilator jest po prostu zbyt wyrozumiały w tym zakresie i zgłasza te naruszenia jako zwykłe "ostrzeżenia".

To, co chciałbym zauważyć, to fakt, że w kilku odpowiedziach można zauważyć stosunkowo dziwną sugestię zwracania void ze swoich funkcji, ponieważ modyfikujesz ciąg znaków w miejscu. Chociaż na pewno zadziała (skoro w rzeczywistości modyfikujesz ciąg znaków w miejscu), nie ma nic złego w zwracaniu tej samej wartości z funkcji. W rzeczywistości jest to raczej standardowa praktyka w języku C tam, gdzie ma to zastosowanie (spójrz na standardowe funkcje, takie jak strcpy i inne), ponieważ umożliwia "łańcuchowanie" wywołań funkcji, jeśli zdecydujesz się na użycie, i kosztuje praktycznie nic, jeśli nie używaj "łączenia".

To powiedziawszy, zadania w twojej implementacji compareString wyglądają kompletnie niepotrzebnie (nawet jeśli niczego nie zepsują). ja też ich pozbyć

int compareString(char cString1[], char cString2[]) { 
    // To lowercase 
    strToLower(cString1); 
    strToLower(cString2); 

    // Do regular strcmp 
    return strcmp(cString1, cString2); 
} 

lub użyć „łańcuchowym” i zrobić

int compareString(char cString1[], char cString2[]) { 
    return strcmp(strToLower(cString1), strToLower(cString2)); 
} 

(to jest, gdy powrócicie char * przyjdzie poręczny). Należy pamiętać, że takie "powiązane" wywołania funkcji są czasami trudne do debugowania za pomocą debuggera krok po kroku.

Jako dodatkową, nierealną notatkę, powiedziałbym, że implementacja funkcji porównywania ciągów w tak destrukcyjny sposób (to modyfikuje ciągi wejściowe) może nie być najlepszym pomysłem. Funkcja nieniszcząca miałaby moim zdaniem znacznie większą wartość. Zamiast wykonywać jawną konwersję ciągów wejściowych na małe litery, zwykle lepszym pomysłem jest zaimplementowanie niestandardowej funkcji porównywania wielkości liter niezwiązanej z wielkością znaków i użycie jej zamiast wywoływania standardu strcmp.

Powiązane problemy