2012-10-17 23 views
7

Próbuję więc dołączyć char do char*.Dodatek C char do char *

Na przykład mam char *word = " "; Mam też char ch = 'x';

robię append(word, ch); Stosując tę ​​metodę ..

void append(char* s, char c) 
{ 

    int len = strlen(s); 
    s[len] = c; 
    s[len+1] = '\0'; 
} 

daje mi błąd segmentacji, i rozumiem, dlaczego sądzę. Ponieważ s[len] jest poza zakresem. Jak sprawić, żeby to działało? Muszę również wyczyścić char*, gdybym użył czegoś w rodzaju char word [500]; Jak mam to wyjaśnić, skoro ma do niego dołączone jakieś postacie? Czy strlen z tego będzie zawsze 500? Z góry dziękuję.

+2

"Ponieważ s [len] jest poza zasięgiem." <- Bardzo dobrze dostrzeżony dla początkującego! Gratulacje. Jednak nadal masz inny błąd - literał łańcuchowy jest tylko do odczytu, nie możesz modyfikować jego zawartości. –

+2

@ H2CO3 's [len + 1]' jest poza zakresem. 's [len]' jest bajtem zerowym, który nie jest liczony przez 'strlen'. – pmr

+0

@pmr yep, technicznie w porządku. Zamiast tego powinienem napisać "sizeof (s)". –

Odpowiedz

10

Typowa praktyka C byłoby jak:

//returns 1 if failed, 0 if succeeded 
int append(char*s, size_t size, char c) { 
    if(strlen(s) + 1 >= size) { 
      return 1; 
    } 
    int len = strlen(s); 
    s[len] = c; 
    s[len+1] = '\0'; 
    return 0; 
} 

Po przejściu funkcję tablicę zmodyfikować funkcję nie ma pojęcia, w czasie kompilacji, ile miejsca ma. Zwykła praktyka w języku C ma również przekazać długość tablicy, a funkcja zaufa temu związanemu i nie powiedzie się, jeśli nie może wykonać swojej pracy w przestrzeni, którą posiada. Inną opcją jest ponowne przydzielenie i zwrócenie nowej tablicy, musisz zwrócić char* lub przyjąć char** jako dane wejściowe, ale musisz pomyśleć dokładnie, jak zarządzać pamięcią sterty w tej sytuacji. Ale bez ponownego przydziału, tak, twoja funkcja musi być jakoś nie powiodła się, jeśli zostanie poproszony o dołączenie, gdy nie ma wolnego miejsca, to zależy od ciebie, jak nie.

+0

To jest zła odpowiedź, ponieważ nie wiesz, czy * s zawiera ciągi literałów. Zazwyczaj są one przechowywane w pamięci tylko do odczytu, co może skutkować naruszeniem dostępu w przypadku ich modyfikacji. Twój kod może działać, ale jest uważany za niezdefiniowane zachowanie. – user1888162

+0

@ user1888162 to również UB, jeśli przekazujesz dużą liczbę dla rozmiaru. – djechlin

3

Jeśli jesteś przejazdem w

append("foo", 'X'); 

załamie, bo foo jest zwykle umieścić w pamięci tylko do odczytu. Nawet jeśli tak nie jest, prawdopodobnie nadpisze coś złego! W tym przypadku kompilator, jeśli jest uprzejmy, powinien ostrzec cię przed zamianą z const char * na char *, co byłoby wskazówką.

5

Trudno dołączyć do łańcucha w miejscu w C. Spróbuj czegoś takiego:

char *append(const char *s, char c) { 
    int len = strlen(s); 
    char buf[len+2]; 
    strcpy(buf, s); 
    buf[len] = c; 
    buf[len + 1] = 0; 
    return strdup(buf); 
} 

Koniecznie deallocate zwrócony ciąg, gdy z nim zrobić.

FYI: Prawdopodobnie jest to spowodowane tym, że ciąg, który przechodzisz, jest przechowywany w pamięci tylko do odczytu. Ale masz rację, ty też spisujesz się pod koniec (zapis [len+1], a nie).

+0

char buf [len + 2] może się nie skompilować, w zależności od wersji swojego kompilatora –

0

Tak, twoje założenie jest - prawie - poprawne - może to być spowodowane tym, że próbujesz pisać poza granicami ciągu znaków (w rzeczywistości tylko s[strlen(s) + 1] jest poza zasięgiem, ponieważ s[strlen(s)] jest nadal prawidłową lokalizacją - kończący się bajt NUL jest tam zapisany). Ale nie możesz także modyfikować literału ciągłego, ponieważ zwykle znajduje się on w jakiejś części pamięci procesu. Oba te działania prowadzą do wywoływania niezdefiniowanych zachowań, które mogą ulec awarii. Możesz rozwiązać ten problem, kopiując ciąg do dynamicznie przydzielanej pamięci, a następnie modyfikując kopię. Ponadto, w argumencie twojej funkcji powinieneś użyć const char *, ponieważ char * sugeruje, że ciągi tekstowe tylko do odczytu nie mogą być przekazywane.

char *append(const char *orig, char c) 
{ 
    size_t sz = strlen(orig); 
    char *str = malloc(sz + 2); 
    strcpy(str, orig); 
    str[sz] = c; 
    str[sz + 1] = '\0'; 
    return str; 
} 

Ponadto, nie zapomnij free() zwrócony ciąg, gdy nie jest już potrzebny.

0

Nie można naprawdę bezpiecznie dołączyć do dowolnego ciągu, ponieważ po pierwsze, stałe ciągów są zwykle w pamięci tylko do odczytu, więc próba zapisu do nich może spowodować błąd segmentacji, a po drugie, masz nie ma gwarancji, że jeśli przekazali ci bufor, którego nie strzeliłeś do końca.

W szczególności, jeśli robisz znak x [500];

Nie ma gwarancji, że strlen (x) zwróci ci 500. Zwróci ci liczbę znaków, które musi odliczać od początku x, zanim osiągnie wartość zerową. Może zwrócić Ci 0, 1 ... 500, 501 ..., w zależności od tego, co jest w x.

Naprawdę jedynymi dostępnymi opcjami są wywołanie append z rozmiarem bufora, do którego się dodajesz (abyś mógł zrobić coś odpowiedniego, jeśli bufor jest pełny) lub aby dodać nowy bufor za każdym razem, gdy zostanie wywołany, w takim przypadku konieczne będzie oczywiście ponowne zwolnienie bufora.