假设我们有一串用逗号分隔的单词。 我想用C编写代码以将这些单词存储在变量中。
示例
amazon, google, facebook, twitter, salesforce, sfb
我们不知道有多少个单词。
如果我要使用C语言执行此操作,我认为我需要进行2次迭代。 第一次迭代,我计算出有多少个单词。 然后,在下一次迭代中,我将存储每个单词。
Step 1: 1st loop -- count number of words
....
....
//End 1st loop. num_words is set.
Step 2:
// Do malloc using num_words.
char **array = (char**)malloc(num_words* sizeof(char*));
Step 3: 2nd loop -- Store each word.
// First, walk until the delimiter and determine the length of the word
// Once len_word is determined, do malloc
*array= (char*)malloc(len_word * sizeof(char));
// And then store the word to it
// Do this for all words and then the 2nd loop terminates
这可以更有效地完成吗? 我不喜欢有2个循环。我认为必须有一种方法可以只使用基本指针在1个循环中完成该操作。
唯一的限制是这需要用C语言完成(由于约束不在我的控制之内)
答案 0 :(得分:1)
您无需另外进行遍历即可计算单词数。一次读取数据时,可以使用realloc
快速扩展数组。
要解析输入行缓冲区,可以使用strtok
来标记各个单词。
将已解析的单词保存到单词列表数组中时,可以使用strdup
创建标记单词的副本。这对于 persist 来说是必要的。也就是说,当您读取第二行时,您在第一行的行缓冲区中指向的内容都会被破坏(依此类推……)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
char **words;
size_t wordmax;
size_t wordcount;
int
main(int argc,char **argv)
{
char *cp;
char *bp;
FILE *fi;
char buf[5000];
--argc;
++argv;
// get input file name
cp = *argv;
if (cp == NULL) {
printf("no file specified\n");
exit(1);
}
// open input file
fi = fopen(cp,"r");
if (fi == NULL) {
printf("unable to open file '%s' -- %s\n",cp,strerror(errno));
exit(1);
}
while (1) {
// read in next line -- bug out if EOF
cp = fgets(buf,sizeof(buf),fi);
if (cp == NULL)
break;
bp = buf;
while (1) {
// tokenize the word
cp = strtok(bp," \t,\n");
if (cp == NULL)
break;
bp = NULL;
// expand the space allocated for the word list [if necessary]
if (wordcount >= wordmax) {
// this is an expensive operation so don't do it too often
wordmax += 100;
words = realloc(words,(wordmax + 1) * sizeof(char *));
if (words == NULL) {
printf("out of memory\n");
exit(1);
}
}
// get a persistent copy of the word text
cp = strdup(cp);
if (cp == NULL) {
printf("out of memory\n");
exit(1);
}
// save the word into the word array
words[wordcount++] = cp;
}
}
// close the input file
fclose(fi);
// add a null terminator
words[wordcount] = NULL;
// trim the array to exactly what we need/used
words = realloc(words,(wordcount + 1) * sizeof(char *));
// NOTE: because we added the terminator, _either_ of these loops will
// print the word list
#if 1
for (size_t idx = 0; idx < wordcount; ++idx)
printf("%s\n",words[idx]);
#else
for (char **word = words; *word != NULL; ++word)
printf("%s\n",*word);
#endif
return 0;
}
答案 1 :(得分:0)
您正在寻找的是 http://manpagesfr.free.fr/man/man3/strtok.3.html
(从手册页开始)
strtok()函数将字符串解析为令牌序列。首次调用strtok()时,应在str中指定要解析的字符串。在随后的每个应解析相同字符串的调用中,str应该为NULL。
但是该线程看起来像Split string with delimiters in C的副本 除非您被迫制作自己的实现...
答案 2 :(得分:0)
我们不知道有多少个单词。
我们知道num_words <= strlen(string) + 1
。仅需要1个“循环”。此处的作弊行为是s
通过strlen()
的快速失败。
// *alloc() out-of-memory checking omitted for brevity
char **parse_csv(const char *s) {
size_t slen = strlen(s);
size_t num_words = 0;
char **words = malloc(sizeof *words * (slen + 1));
// find, allocate, copy the words
while (*s) {
size_t len = strcspn(s, ",");
words[num_words] = malloc(len + 1);
memcpy(words[num_words], s, len);
words[num_words][len] = '\0';
num_words++;
s += len; // skip word
if (*s) s++; // skip ,
}
// Only 1 realloc() needed.
realloc(words, sizeof *words *num_words); // right-size words list
return words;
}
它使发送到NULL
终止列表,所以
char **words = malloc(sizeof *words * (slen + 1 + 1));
...
words[num_words++] = NULL;
realloc(words, sizeof *words *num_words);
return words;
在考虑初始char **words = malloc(...);
的最坏情况时,我选择了一个像",,,"
这样的字符串,它的3个','
代表4个单词""
,{{1} },""
,""
。对于此类病理情况,请根据需要调整代码。