2017-01-24 12 views
0

Я работаю над функцией C, которая должна вводить строку и удалять все символы, отличные от буквы, только в начале. Например, если входная строка была "123 456 My dog has fleas." то выходная строка должна быть: "My dog has fleas."Как изящно перемещать строку в C до конца

Вот что у меня есть, который работает на примере выше:

int isALetter(char x){ 
    // Checks to see is x is an ASCII letter 
    if( ((int)x>=65 && (int)x<=90) || ((int)x>=97 && (int)x<=122) ) 
     return 0;  // TRUE 
    return 1;   // FALSE 
} 
char* removeNonLettersAtBeginning(char* str){ 
    while(isALetter(str[0]) == 1 && &str[0] != NULL) 
     str++; 
    return str; 
} 

Вот что мне ошибок ... Если строка не имеет писем вообще, код, похоже, не работает. Если я отправлю строку " " (никаких писем), я получаю «XDG_SESSION_ID=3818». Я не знаю, что это за строка, но я принимаю его «мусор» в системе.

Но моя функция removeNonLettersAtBeginning() должна возвращать строку "", пустую строку. Я не могу понять, в чем проблема, но я держу пари, что он лежит здесь:

while(isALetter(str[0]) == 1 && &str[0] != NULL) 

"&str[0] != NULL" часть этой линии, чтобы гарантировать, что я не стекать с конца строки; Я пытаюсь проверить, не ударил ли я символ Null, который завершает строку. Кто-нибудь видит, где я ошибаюсь?

+0

'& str [0]! = NULL' должен прибыть перед' isALetter (str [0]) '. Если 'str == NULL' вы пытаетесь разыменовать его. –

+2

Несвязанный, но 'if (((int) x> = 65 && (int) x <= 90) || ((int) x> = 97 && (int) x <= 122))' -> 'if ((x> = 'A' && x <= 'Z') || (x> = 'a' && x <= 'z')) ' – yano

+1

'& str [0]! = NULL' неверно. & str [0] == str, поэтому он никогда не будет NULL. Вы должны использовать 'str [0]! =' \ 0 ' –

ответ

1

Вот другой подход.

#include <ctype.h> 
... 
void stripNonAlpha(char *str) 
{ 
    size_t r = 0, w = 0; // read and write indices 

    /** 
    * Find the first alpha character in the string 
    */ 
    while (str[r] && !isalpha(str[r])) 
    r++; 

    /** 
    * Shift remaining characters to the left, including the 0 terminator 
    */ 
    while ((str[w++] = str[r++])) 
    ; //empty loop 
} 

В основном, этот код выполняет поиск первого алфавитного символа в строке; после обнаружения этот символ и все последующие символы копируются по начальной части строки. Например, возьмем строку "123 test". Первоначально, вот что все выглядит следующим образом:

r 
    | 
    v 
+---+---+---+---+---+---+---+---+---+ 
|'1'|'2'|'3'|' '|'t'|'e'|'s'|'t'| 0 | 
+---+---+---+---+---+---+---+---+---+ 
^
    | 
    w 

Первый цикл проверяет значение символа с индексом r; в то время как это не конец строки или альфа-символ, продвигайтесь вперед r.В конце цикла, мы имеем следующее:

    r 
        | 
        v 
+---+---+---+---+---+---+---+---+---+ 
|'1'|'2'|'3'|' '|'t'|'e'|'s'|'t'| 0 | 
+---+---+---+---+---+---+---+---+---+ 
^
    | 
    w 

Второй копирует цикл символов из r и записывает их в w (до и включая 0 терминатор), например так:

     r 
         | 
         v 
+---+---+---+---+---+---+---+---+---+ 
|'t'|'2'|'3'|' '|'t'|'e'|'s'|'t'| 0 | 
+---+---+---+---+---+---+---+---+---+ 
    ^
     | 
     w 
          r 
          | 
          v 
+---+---+---+---+---+---+---+---+---+ 
|'t'|'e'|'3'|' '|'t'|'e'|'s'|'t'| 0 | 
+---+---+---+---+---+---+---+---+---+ 
     ^
      | 
      w 
           r 
           | 
           v 
+---+---+---+---+---+---+---+---+---+ 
|'t'|'e'|'s'|' '|'t'|'e'|'s'|'t'| 0 | 
+---+---+---+---+---+---+---+---+---+ 
      ^
       | 
       w 
            r 
            | 
            v 
+---+---+---+---+---+---+---+---+---+ 
|'t'|'e'|'s'|'t'|'t'|'e'|'s'|'t'| 0 | 
+---+---+---+---+---+---+---+---+---+ 
       ^
        | 
        w 
             r 
             | 
             v 
+---+---+---+---+---+---+---+---+---+ 
|'t'|'e'|'s'|'t'| 0 |'e'|'s'|'t'| 0 | 
+---+---+---+---+---+---+---+---+---+ 
        ^
         | 
         w 

Некоторые результаты выборки:

$ ./stripper "123 345 this is a test" 
before: "123 345 this is a test" 
after: "this is a test" 

$ ./stripper "this is a test" 
before: "this is a test" 
after: "this is a test" 

$ ./stripper "   " 
before: "   " 
after: "" 

$ ./stripper "12345" 
before: "12345" 
after: "" 

$ ./stripper "12345 abc 23456" 
before: "12345 abc 23456" 
after: "abc 23456" 

Очевидно, что эта операция разрушительна - входная строка изменена. Если вы этого не хотите, вам нужно будет написать другую целевую строку. Это должно быть достаточно легко понять.

2

Вы проверка нулевого терминатора является неправильной, нулевым терминатор '\0' не NULL

#include <stdio.h> 

int isALetter(char x){ 
    // Checks to see is x is an ASCII letter 
    if((x>='A' && x<='Z') || (x>='a' && x<='z')) 
     return 0;  // TRUE 
    return 1;   // FALSE 
} 
char* removeNonLettersAtBeginning(char* str){ 
    if (str != NULL) 
    { 
     while(isALetter(*str) == 1 && *str != '\0') 
     str++; 
    } 
    return str; 
} 

int main (void) 
{ 
    char test_string[] = "  test\n"; 
    char *test_ptr = test_string; 

    printf ("%s", test_ptr); 

    test_ptr = removeNonLettersAtBeginning(test_ptr); 

    printf ("%s", test_ptr); 
} 

В качестве примечания, чтобы сделать код более читабельным, избегайте использования магических чисел как 65, 90. Вы можете, как показано на рисунке, легко использовать символы, чтобы сделать это: 'A', 'Z' ...

+0

Я думаю, что главная проблема заключалась не в 'NULL', а в дополнительном' & '. (Но, да, '' \ 0'' является гораздо лучшей нулевой константой символа.) –

+1

Строго говоря, 'x> = 'A' && x <= 'Z'' не является правильным решением, так как оно может потерпеть неудачу на некоторых неясных наборах символов, отличных от ASCII. Гораздо лучше использовать 'isalpha()' от ''. –

2

Вы пишете:

while(isALetter(str[0]) == 1 && &str[0] != NULL) //error in str[0] 
     str++;           //it must be *str 

здесь, вы использовали обугленного * ул, которая указывает на строку, которая должна быть испытания.

Как вы сказали, вы хотите удалить все несимволы из строки. но, вы используете неправильный указатель типа char.

безошибочным код:

while(isALetter(*str) == 1 && *str != '\0') 
      str++;   

она должна быть работа для и в пользу :)

+0

Почему это «неправильный путь»? Разве это не похоже на компилятор? – TWhelan

+0

Да, какой-то старый компилятор, такой как turbo, все еще страдает. –