在C中创建动态大小的2D数组

时间:2018-11-10 19:06:21

标签: c pointers

假设我们有一串用逗号分隔的单词。 我想用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语言完成(由于约束不在我的控制之内)

3 个答案:

答案 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} },""""。对于此类病理情况,请根据需要调整代码。