C - 将字符串(句子)转换为字符串列表

时间:2017-01-13 09:23:57

标签: c string pointers char

我需要复制一个句子,例如" Hello world"到一个字符串列表,意思是一个char数组,其中每2个单词由'\0'分隔。 请注意,单词被定义为没有空格的行中任意数量的字符。

因此,每当我的程序检测到一行中的任何数量的空白区域(仅包括1个空白区域)时,它应该会改变一个'\0'

问题是,在'\0'字符数组中第一次写target之后,我再也无法写信了。我猜它是因为'\0'意味着字符串结束但在我的情况下我试图在字符数组中实现一个字符串列表,所以我必须在每两个字之间有'\0'

基本上我的问题是如何在放置'\0'之后计算写入char数组?

到目前为止,这是我的代码(正如您所看到的,我在每次迭代时都会在traget中检查足够的空间,但该部分工作正常,因此并非真正有用)

int strListFromWords(const char* source, char* target, int buffSize)
{
    if (buffSize < 2) return -1;
    char* sCurrentPointer = source;
    char* tCurrentPointer = target;
    int charsInTarget = 0;
    while (*sCurrentPointer != '\0')            // While not end of string
    {
        if (charsInTarget + 2 < buffSize)   // if there is enough space in target for current char 
        {
            charsInTarget++;
            if (!isspace(*sCurrentPointer))         // if current char isn't space
            {
                *tCurrentPointer = *sCurrentPointer;
                sCurrentPointer++;
                tCurrentPointer++;
            }
            else
            {
                *tCurrentPointer = '\0';            // PROBLEMATIC LINE put '\0' instead of spcace (in target)

                sCurrentPointer++;                  // goto next char in source
                tCurrentPointer++;                  // goto next position in target
                while (isspace(*sCurrentPointer))   // while there are more spaces in a row
                {
                    sCurrentPointer++;              // just skip them without messing with target
                }
            }
        }
        else
            {                                   // Not enough space
                emptyStrList(target);
                return 0;
            }
        }
    *tCurrentPointer = '\0';
    *(tCurrentPointer + 1) = '\0';
    return numStrsInList(target);
    }

谢谢,

4 个答案:

答案 0 :(得分:1)

我认为主要问题在于要求的制定。

如果要求是“将一个句子分成单词”,那么结果应该是一个“单词”数组,意思是一个字符串数组。如果这是要求,那么该函数应该具有类似char **getWordsArrayFromSentence(const char* sentence)的签名。当你提出不同的签名时,我认为你的要求是不同的。

您的方法的签名是int strListFromWords(const char* source, char* target, int buffSize),这表明它是关于从源到目标的复制,同时用单个分隔符替换每个空格序列。

如果您选择字符;作为分隔符,则句子"Hello world"的结果应为"Hello;world";您可以打印结果,例如使用printf("%s", target),可以检查您的算法是否正常工作。

但是,如果您选择字符串终止字符'\0'作为分隔符,则结果看起来好像只包含第一个单词(尽管目标的其余部分也包含其他单词):{{1} } target "Hello\0world\0"代表字符串终止字符。然后,当您使用\0打印目标时,输出为printf("%s", target),即直到第一个字符串终止字符的目标内容。

因此,签名Hello产生一个统一的字符序列,但不是单词的“列表”; “单词”实际上包含在目标中,但是您没有可以直接访问每个单词的数据结构。

BTW:请注意以下几行是有问题的,

int strListFromWords(const char* source, char* target, int buffSize)

因为你指定了*tCurrentPointer = "\0"; *(tCurrentPointer + 1) = "\0"; ,它是目标中的一个字符,一个指针值,即指向字符串*tCurrentPointer的指针;相反,你应该写

"\0"

(注意单引号)。

答案 1 :(得分:1)

没有什么可以阻止你写过0。

我使用以下代码段测试了您的函数,并正确返回word_count。目标缓冲区将包含0个已终止的字,最后加上一个额外的0。我猜,那是意图。

#include <conio.h> // for getch()
#include <malloc.h>
#include <string.h>

int main()
{
   char* source = " Hello World!\nThis is line number two.\n\n \n  \n This is the last line";

   size_t buflen = strlen(source);
   char* target = (char*)malloc(strlen(source));

   int word_count = strListFromWords(source, target, buflen);
   printTarget(target);

   free(target);
   getch();
}

此功能将显示整个目标缓冲区:

void printTarget(const char* target) {
       char prev = ' ';
       for (int i = 0;; i++) {
          if (target[i])
             putch(target[i]);
          else {
             putch('\n');
             if (!prev)
                break;
          }
          prev = target[i];
       }
    }

为了使其编译,有必要进行一些小的改动:

#include <stdio.h>
#include <ctype.h>

int strListFromWords(const char* source, char* target, int buffSize)
{
   if (buffSize < 2) return -1;
   char* sCurrentPointer = (char*)source;
   char* tCurrentPointer = target;
   int charsInTarget = 0;
   int numStrsInList = 0;

   while (*sCurrentPointer != '\0')            // While not end of string
   {
      if (charsInTarget + 2 < buffSize)   // if there is enough space in target for current char 
      {
         charsInTarget++;
         if (!isspace(*sCurrentPointer))         // if current char isn't space
         {
            *tCurrentPointer = *sCurrentPointer;
            sCurrentPointer++;
            tCurrentPointer++;
         }
         else
         {
            *tCurrentPointer = '\0';            // PROBLEMATIC LINE put '\0' instead of spcace (in target)
            numStrsInList++;

            sCurrentPointer++;                  // goto next char in source
            tCurrentPointer++;                  // goto next position in target
            while (isspace(*sCurrentPointer))   // while there are more spaces in a row
            {
               sCurrentPointer++;              // just skip them without messing with target
            }
         }
      }
      else
      {                                   // Not enough space
         //emptyStrList(target);
         return 0;
      }
   }

   *tCurrentPointer = 0;
   *(tCurrentPointer + 1) = 0;
   return numStrsInList;
}

请注意,我只解决了被问到的问题。

答案 2 :(得分:1)

你不是很远。好的还有一些问题需要解决:

int strListFromWords(const char* source, char* target, int buffSize)
{
    if (buffSize < 2) return -1;
    //char* sCurrentPointer = source;  lose const qualifier
    const char* sCurrentPointer = source;  // better!

甚至更好:

int strListFromWords(const char* sCurrentPointer, char* target, int buffSize)
{
    if (buffSize < 2) return -1;
    char* tCurrentPointer = target;

主要是:

/* *tCurrentPointer = "\0";
*(tCurrentPointer + 1) = "\0";  NO! "\0" is a char ARRAY */
*tCurrentPointer = '\0';
*(tCurrentPointer + 1) = '\0';

但除此之外,您的代码执行预期的操作...终止'\0'不会锁定数组。它只是标记将使用的字符串的结尾但是所有字符串函数,但是如果您仍然在数组中,则可以在'\0'之后写入。

您可以使用该代码控制它:

int numStrsInList(char *target) {
    int n = 0;
    while (*target) {
        target += strlen(target) + 1; // skip past the '\0'
        n += 1;
    }
    return n;
}
int strListFromWords(const char* source, char* target, int buffSize)
...
int main() {
    char target[32];
    char src[] = "Hello to  the    world";
    int n;
    char *ix = target;

    n = strListFromWords(src, target, sizeof(target));
    printf("%d words:", n);
    while (*ix) {
        printf(" >%s<", ix);
        ix += strlen(ix) + 1;
    }
    putchar('\n');
    return 0;
}

按预期输出:

4 words: >Hello< >to< >the< >world<

答案 3 :(得分:0)

*tCurrentPointer = "\0";

*tCurrentPointer的类型为char;您不能将数组(或自动转换后的指针)分配给char。

我建议您打开所有编译器警告并注意它们。