Разделить строку в C каждый пробел - PullRequest
51 голосов
/ 22 декабря 2010

Я хочу написать программу на C, которая отображает каждое слово целого предложения (взятого как ввод) в отдельной строке.Это то, что я сделал до сих пор:


void manipulate(char *buffer);
int get_words(char *buffer);

int main(){
    char buff[100];

    printf("sizeof %d\nstrlen %d\n", sizeof(buff), strlen(buff));   // Debugging reasons

    bzero(buff, sizeof(buff));

    printf("Give me the text:\n");
    fgets(buff, sizeof(buff), stdin);

    manipulate(buff);
    return 0;
}

int get_words(char *buffer){                                        // Function that gets the word count, by counting the spaces.
    int count;
    int wordcount = 0;
    char ch;

    for (count = 0; count < strlen(buffer); count ++){
        ch = buffer[count];
        if((isblank(ch)) || (buffer[count] == '\0')){                   // if the character is blank, or null byte add 1 to the wordcounter
            wordcount += 1;
        }
    }
    printf("%d\n\n", wordcount);
    return wordcount;
}

void manipulate(char *buffer){
    int words = get_words(buffer);
    char *newbuff[words];
    char *ptr;
    int count = 0;
    int count2 = 0;
    char ch = '\n';

    ptr = buffer;
    bzero(newbuff, sizeof(newbuff));

    for (count = 0; count < 100; count ++){
        ch = buffer[count];
        if (isblank(ch) || buffer[count] == '\0'){
            buffer[count] = '\0';
            if((newbuff[count2] = (char *)malloc(strlen(buffer))) == NULL) {
                printf("MALLOC ERROR!\n");
                exit(-1);
            }
            strcpy(newbuff[count2], ptr);
            printf("\n%s\n",newbuff[count2]);
            ptr = &buffer[count + 1];
            count2 ++;
        }
    }
}

Хотя вывод - то, что я хочу, у меня действительно много черных пробелов после отображения последнего слова, и malloc () возвращаетNULL так ОШИБКА МАЛЛОКА!отображается в конце.Я могу понять, что в моей реализации malloc () есть ошибка, но я не знаю, что это такое.

Есть ли другой, более элегантный - как правило, лучший способ сделать это?

Заранее спасибо.

Ответы [ 8 ]

81 голосов
/ 22 декабря 2010

http://www.cplusplus.com/reference/clibrary/cstring/strtok/

Взгляните на это и используйте пробельные символы в качестве разделителя. Если вам нужно больше подсказок, дайте мне знать.

С сайта:

char * strtok ( char * str, const char * delimiters );

При первом вызове функция ожидает строку C в качестве аргумента для str, чей первый символ используется в качестве начального местоположения для сканирования токенов. При последующих вызовах функция ожидает нулевой указатель и использует позицию сразу после конца последнего токена в качестве нового начального местоположения для сканирования.

Если в вызове strtok найден завершающий нулевой символ str, все последующие вызовы этой функции (с нулевым указателем в качестве первого аргумента) возвращают нулевой указатель.

Параметры

  • ул
    • Строка C для усечения.
    • Обратите внимание, что эта строка модифицируется путем разбивки на более мелкие строки (токены). В качестве альтернативы [sic] может быть указан нулевой указатель, и в этом случае функция продолжает сканирование после завершения предыдущего успешного вызова функции.
  • разделители
    • Строка C, содержащая символы-разделители.
    • Они могут варьироваться от одного звонка к другому.

Возвращаемое значение

Указатель на последний токен, найденный в строке. Пустой указатель возвращается, если не осталось токенов для извлечения.

* +1037 * Пример * +1038 *
/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}
4 голосов
/ 22 декабря 2010

Для забавы вот реализация, основанная на подходе обратного вызова:

const char* find(const char* s,
                 const char* e,
                 int (*pred)(char))
{
    while( s != e && !pred(*s) ) ++s;
    return s;
}

void split_on_ws(const char* s,
                 const char* e,
                 void (*callback)(const char*, const char*))
{
    const char* p = s;
    while( s != e ) {
        s = find(s, e, isspace);
        callback(p, s);
        p = s = find(s, e, isnotspace);
    }
}

void handle_word(const char* s, const char* e)
{
    // handle the word that starts at s and ends at e
}

int main()
{
    split_on_ws(some_str, some_str + strlen(some_str), handle_word);
}
1 голос
/ 23 декабря 2010

Попробуйте использовать strtok_r, как предлагали другие, или что-то вроде:

void printWords(const char *string) {
    // Make a local copy of the string that we can manipulate.
    char * const copy = strdup(string);
    char *space = copy;
    // Find the next space in the string, and replace it with a newline.
    while (space = strchr(space,' ')) *space = '\n';
    // There are no more spaces in the string; print out our modified copy.
    printf("%s\n", copy);
    // Free our local copy
    free(copy);
}
1 голос
/ 22 декабря 2010

malloc(0) может (необязательно) вернуть NULL, в зависимости от реализации. Вы понимаете, почему вы можете звонить malloc(0)? Или, точнее, вы видите, где вы читаете и пишете за пределами своих массивов?

0 голосов
/ 25 июня 2015
char arr[50];
gets(arr);
int c=0,i,l;
l=strlen(arr);

    for(i=0;i<l;i++){
        if(arr[i]==32){
            printf("\n");
        }
        else
        printf("%c",arr[i]);
    }
0 голосов
/ 22 декабря 2010

Так же, как идея другого стиля работы со строками в C, вот пример, который не изменяет исходную строку и не использует malloc. Для поиска пробелов я использую функцию libc strpbrk.

int print_words(const char *string, FILE *f)
{
   static const char space_characters[] = " \t";
   const char *next_space;

   // Find the next space in the string
   //
   while ((next_space = strpbrk(string, space_characters)))
   {
      const char *p;

      // If there are non-space characters between what we found
      // and what we started from, print them.
      //
      if (next_space != string)
      {
         for (p=string; p<next_space; p++)
         {
            if(fputc(*p, f) == EOF)
            {
               return -1;
            }
         }

         // Print a newline
         //
         if (fputc('\n', f) == EOF)
         {
            return -1;
         }
      }

      // Advance next_space until we hit a non-space character
      //
      while (*next_space && strchr(space_characters, *next_space))
      {
         next_space++;
      }

      // Advance the string
      //
      string = next_space;
   }

   // Handle the case where there are no spaces left in the string
   //
   if (*string)
   {
      if (fprintf(f, "%s\n", string) < 0)
      {
         return -1;
      }
   }

   return 0;
}
0 голосов
/ 22 декабря 2010

Вы должны быть malloc'ing strlen (ptr), а не strlen (buf). Кроме того, ваш счетчик2 должен быть ограничен количеством слов. Когда вы доберетесь до конца вашей строки, вы продолжите переходить нули в буфере и добавлять строки нулевого размера в ваш массив.

0 голосов
/ 22 декабря 2010

Что-то идет не так: get_words() всегда возвращает на единицу меньше фактического количества слов, поэтому в конечном итоге вы пытаетесь:

char *newbuff[words]; /* Words is one less than the actual number,
so this is declared to be too small. */

newbuff[count2] = (char *)malloc(strlen(buffer))

count2, в конце концов, всегда на единицу больше, чем количество элементовВы объявили для newbuff[].Почему malloc() не возвращает правильный ptr, хотя, я не знаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...