上周,我为班级分配了一个作业,其中我必须使用空格,制表符和\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);
}
返回单词长度和单词数量的函数可以正常工作,所以我认为问题出在主函数上。
答案 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'的源字符串的内容,以终止找到的字符串。
此处实现的功能是:
代码:
#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_word
或ft_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;
}