在字符串中拆分空格,并将其存储在不带库的C表中

时间:2018-08-08 06:45:24

标签: c string malloc

上周,我为班级分配了一个作业,其中我必须使用空格,制表符和\n作为分隔符来分割字符串,并将每个“单词”存储在数组中。我想我很亲密,但是我的输出很奇怪,所以如果有人可以告诉我我忘记了什么,那会很好。唯一的事情是我只能使用malloc

char    **ft_split_whitespaces(char *str)
{
    int     i;
    int     j;
    int     k;
    char    **tab;

    i = 0;
    j = 0;
    k = 0;
    tab = (char**)malloc(sizeof(*tab) * (ft_nb_words(str) + 1));
    while (str[i])
    {
        while (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
            i++;
        if (str[i])
        {
            if ((tab[j] = (char*)malloc(sizeof(char) * (ft_len_word(str + i) + 1))) == NULL)
                return (NULL);
            while (k < ft_len_word(str + i))
                tab[j][k++] = str[i++];
            tab[j++][k] = '\0';
            k = 0;
        }
    }
    tab[j] = NULL;
    return (tab);
}

返回单词长度和单词数量的函数可以正常工作,所以我认为问题出在主函数上。

4 个答案:

答案 0 :(得分:1)

如果您使用一个指针指向最后一次出现的特定字符('''\ n'\ t),则可以轻松地处理此问题。

   char    **ft_split_whitespaces(char *str)
    {
    int     i;
    int     j;
    int     k;
    char    **tab;
    char *prevToken=str;

    i = 0;
    j = 0;
    k = 0;
    tab = (char**)malloc(sizeof(*tab) * (ft_nb_words(str) + 1));
    while (str[i] != '\0')
    {

        if(str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
        {
            i++;
            if ((tab[j] = (char*)malloc(sizeof(char) * (ft_len_word(prevToken) + 1))) == NULL)
                return (NULL);

            while (k < ft_len_word(prevToken) &&
                (prevToken[k] !=' ' &&  prevToken[k] != '\t' &&  prevToken[k] != '\n'))
                tab[j][k] = prevToken[k++];

            printf("tab=%s\n", tab[j]);
            k = 0;
            j++;
            prevToken=(str+i);
        }
        else{
           i++;
         }
    }

      /* to handle the last word */
            if ((tab[j] = (char*)malloc(sizeof(char) * (ft_len_word(prevToken) + 1))) == NULL)
                return (NULL);

            while (k < ft_len_word(prevToken) &&
                (prevToken[k] !=' ' &&  prevToken[k] != '\t' &&  prevToken[k] != '\n'))
                tab[j][k] = prevToken[k++];
            printf("tab=%s\n", tab[j]);


    tab[j] = NULL;
    return (tab);
    }

答案 1 :(得分:1)

以下代码包含一些有用的C函数的实现。

您搜索的功能是strtok()。在代码中还实现了功能strspn()strpbrk(),因为strtok()使用了它们。

解决此类问题的最佳方法是研究C标准函数的实现。

该代码存储最多100个令牌的副本(提取的单词)。

您必须记住,函数strtok()修改了插入'\ 0'的源字符串的内容,以终止找到的字符串。

此处实现的功能是:

  • mystrtok()
  • mystrspn()
  • mystrpbrk()

代码:

#include <stdio.h>
#include <string.h> /* for the use of strcpy fn */
#include <malloc.h>

char * mystrtok (char * s, char * delim);
size_t mystrspn (const char *s, const char *accept);
char * mystrpbrk (const char *s, const char *accept);

char * mystrpbrk (const char *s, const char *accept)
{
    while (*s != '\0')
    {
        const char *a = accept;
        while (*a != '\0')
            if (*a++ == *s)
                return (char *) s;
        ++s;
    }

    return NULL;
}

size_t mystrspn (const char *s, const char *accept)
{
    const char *p;
    const char *a;
    size_t count = 0;

    for (p = s; *p != '\0'; ++p)
    {
        for (a = accept; *a != '\0'; ++a)
            if (*p == *a)
                break;
        if (*a == '\0')
            return count;
        else
            ++count;
    }

    return count;
}

char * mystrtok (char *s, char *delim)
{
    char *token;
    static char *olds;

    if (s == NULL) {
        s = olds;
    }

    /* Scan leading delimiters.  */
    s += mystrspn (s, delim);
    if (*s == '\0')
    {
        olds = s;
        return NULL;
    }

    /* Find the end of the token.  */
    token = s;
    s = mystrpbrk (token, delim);
    if (s == NULL)
    {
        /* This token finishes the string.  */
        while(*olds)
            olds++;
    }
    else
    {
        /* Terminate the token and make OLDS point past it.  */
        *s = '\0';
        olds = s + 1;
    }
    return token;
}

int main(void)
{
    char str[] = "I have an orange\tYou have some bananas\nShe has three pineapples\n";
    char * x = NULL;

    int cnt=0,i;


    char **store;

    /* Stores a max of 100 strings */
    store = malloc(sizeof(char *)*100);

    /* The total space for the tokens is
       max the entire string + '\0' */
    store[0] = malloc(strlen(str)+1);

    /* Extract the first token */
    x=mystrtok(str," \n");
    while(x) {
        printf("Storing %s\n",x);

        /* Store a copy of the token */
        strcpy(store[cnt],x);
        store[cnt+1]=store[cnt]+strlen(x)+1;
        cnt++;

        /* extract the next token */
        x=mystrtok(NULL," \n\t");
    }

    for(i=0;i<cnt;i++)
        printf("Stored %s\n",store[i]);

    free(store[0]);
    free(store);

    return 0;
}

答案 2 :(得分:0)

当您多次调用ft_len_word时,您的代码效率很低,但似乎与malloc失败时的不确定行为没有区别。

问题可能出在您的ft_len_wordft_nb_words版本上。您应该发布一个完整的程序以显示问题,以便进行适当的调查。

这是不使用这些功能的修改版本:

#include <stdlib.h>

int ft_is_space(char c) {
    return (c == ' ' || c == '\t' || c == '\n');
}

char **ft_split_whitespaces(const char *str) {
    int i, j, k, len, in_space, nb_words;
    char **tab;

    nb_words = 0;
    in_space = 1;
    for (i = 0; str[i]; i++) {
        if (ft_is_space(str[i]) {
            in_space = 1;
        } else {
            nb_words += in_space;
            in_space = 0;
        }
    }
    tab = malloc(sizeof(*tab) * (nb_words + 1));
    if (tab != NULL) {
        i = 0;
        j = 0;
        while (str[i]) {
            while (ft_is_space(str[i]))
                i++;
            if (str[i]) {
                for (len = 1; str[i + len] && !ft_is_space(str[i + len]); len++)
                     continue;
                if ((tab[j] = malloc(sizeof(*tab[j]) * (len + 1))) == NULL) {
                     while (j > 0)
                         free(tab[--j]);
                     free(tab);
                     return NULL;
                }
                for (k = 0; k < len; k++)
                    tab[j][k] = str[i + k];
                tab[j++][len] = '\0';
                i += len;
            }
        }
        tab[j] = NULL;
    }
    return tab;
}

答案 3 :(得分:0)

如果您不想使用库功能或需要与strtok()提供的功能不同的功能,则需要实现strtok()的版本。

下面是一个简单的字符串标记器,与标准库的strtok()不同,它在连续定界符的情况下仍返回一个值。我使用此函数来解析CSV文件,该文件有时包含空单元格,因此连续,个字符。标准库的strtok()对我不起作用,因此我必须实现自己的功能。

我使用了其他辅助功能,这些功能现在是a simple string library I maintain on GitHub, called zString的一部分。

下面是它的行为

Example Usage
      char str[] = "A,B,,,C";
      printf("1 %s\n",zstring_strtok(s,","));
      printf("2 %s\n",zstring_strtok(NULL,","));
      printf("3 %s\n",zstring_strtok(NULL,","));
      printf("4 %s\n",zstring_strtok(NULL,","));
      printf("5 %s\n",zstring_strtok(NULL,","));
      printf("6 %s\n",zstring_strtok(NULL,","));

  Example Output
      1 A
      2 B
      3 ,
      4 ,
      5 C
      6 (null)

和代码

char *zstring_strtok(char *str, const char *delim) {
    static char *static_str=0;      /* var to store last address */
    int index=0, strlength=0;       /* integers for indexes */
    int found = 0;                  /* check if delim is found */

    /* delimiter cannot be NULL
    * if no more char left, return NULL as well
    */
    if (delim==0 || (str == 0 && static_str == 0))
        return 0;

    if (str == 0)
        str = static_str;

    /* get length of string */
    while(str[strlength])
        strlength++;

    /* find the first occurrence of delim */
    for (index=0;index<strlength;index++)
        if (str[index]==delim[0]) {
            found=1;
            break;
        }

    /* if delim is not contained in str, return str */
    if (!found) {
        static_str = 0;
        return str;
    }

    /* check for consecutive delimiters
    *if first char is delim, return delim
    */
    if (str[0]==delim[0]) {
        static_str = (str + 1);
        return (char *)delim;
    }

    /* terminate the string
    * this assignment requires char[], so str has to
    * be char[] rather than *char
    */
    str[index] = '\0';

    /* save the rest of the string */
    if ((str + index + 1)!=0)
        static_str = (str + index + 1);
    else
        static_str = 0;

        return str;
}