【问题标题】:error: array type has incomplete element type; dynamic 2D array错误:数组类型的元素类型不完整;动态二维数组
【发布时间】:2018-01-16 02:15:39
【问题描述】:

我应该返回输入字符串共有的字符串单词的二维数组。

#include <stdio.h>
#include <malloc.h>

#define SIZE 31

int strcmp1(char *word1, char *word2, int len) {
    while (len-- > 0) {
        if (!(*word1++ == *word2++))
            return -1;
    }
    return 0;
}

void strcpy1(char *emptyStr, char *str, int len) {
    while (len-- > 0) {
        *emptyStr++ = *str++;
    }
    *emptyStr = '\0';
}

void print(char *str) {
    for (; *str;)
        printf("%c", *str++);
    printf("\n");
}

char **commonWords(char *str1, char *str2) {
    char *temp1, *temp2;
    char commWords[][] = (char**)calloc(10, SIZE);
    int i = 0;

    if (str1 == NULL || str2 == NULL) {
        return NULL;
    }

    for (temp1 = str1; *temp1; ++temp1) {
        if (*temp1 != ' ') {
            str1 = temp1;
            while (*temp1++ != ' ')
                ;
            int len1 = temp1 - str1;
            for (temp2 = str2; *temp2; ++temp2) {
                if (*temp2 ! =' ') {
                    str2 = temp2;
                    while (*temp2++ != ' ')
                        ;
                    int len2 = temp2 - str2;

                    if (len1 == len2) {
                        if (strcmp1(str1, str2, len1)) {
                            strcpy1(commWords[i++], str1, len1);
                        }
                    }
                }
            }
        }
    }
    commWords[i] = NULL;
    return commWords;
}

int main() {
    char *name1 = "abc def ghi";
    char *name2 = "ghi abc jkl";
    char common[][31] = commonWords(name1, name2);
    int i = 0;
    while (common[i++] != NULL) {
        printf("%s\n", common[i]);
    }
}

当我编译这个时,我得到错误:数组类型的元素类型不完整。由于我需要在函数内分配内存,所以我使用calloc 动态分配最多10 个长度为SIZE(定义为31)的常用词。有没有办法不预先声明常用词的数量(即数组的第一维)?为什么我会收到这个错误?这个问题有更优雅的解决方案吗?

【问题讨论】:

  • char commWords[][] = (char**) calloc(10, SIZE); char ** commWords = calloc(10, SIZE);
  • 你能解释一下你的评论吗? @tilz0R
  • @tilz0R 在进行了您提到的更改后,我仍然遇到运行时错误。
  • 指针指针不是数组,也不是多维数组,也不能指向一个。您应该read this 来消除一些常见的误解。

标签: c arrays string multidimensional-array dynamic-memory-allocation


【解决方案1】:

你用错了。

首先,如果您想拥有 2D 动态数组样式,请使用指向指针的指针。 记住,这不是二维数组!

char ** commWords;

然后为指针分配内存:

//Allocate memory for 10 pointers to char
commWords = malloc(sizeof(*commWords) * 10); 

然后,为每个单词分配单独的内存

//Allocate memory for each element for string
for (int i = 0; i < 10; i++) {
    commWords[i] = malloc(sizeof(*commWords[i]) * SIZE); //Allocate memory with length of SIZE
}

然后按预期使用分配的内存。

【讨论】:

  • 你不是用指针数组来声明二维数组吗?我试过了。如果我不知道有多少常用词怎么办?有没有办法不预先声明数组的第一个维度?即便如此,我仍然会遇到运行时错误。
  • 指针指针不是数组,也不是多维数组,也不能指向一个。您应该read this 来消除一些常见的误解。
  • @ritika_13 “如果我不知道有多少常用词怎么办?”您可以将报告的常用词的数量限制为 10(或其他)。或者您可以realloc 指针数组来添加更多常用词。或者您可以计算其中一个字符串中的单词数,并将其用作常用单词数的上限。
【解决方案2】:

你的代码有很多问题:

  • 数组数组(也称为二维数组)与指向数组的指针数组不同。混合2是不正确的,必然会失败。

  • maincommon 的定义不正确:char commWords[][] = (char**)calloc(10, SIZE);。你可以这样解决:

    char (*commWords)[SIZE] = calloc(sizeof(*commWords), 10);
    

    但其余代码与 commWords 作为二维数组不一致,定义 commonWords() 以返回指向数组数组的指针的语法将非常复杂。

  • 用于打印公共字符串的while 循环也是虚假的:在printf() 语句中使用它之前,您先增加i

这是实现目标的更经典方法,使用指向字符串的指针数组,以及标准但很少使用的函数strspn()strcspn()

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void freeWords(char **arr) {
    if (arr) {
        for (size_t i = 0; arr[i]; i++) {
            free(arr[i]);
        }
        free(arr);
    }
}

/* return a NULL terminated array of strings or NULL upon memory allocation failure */
char **commonWords(const char *str1, const char *str2) {
    size_t n = 0;
    char **common = calloc(sizeof(*common), n + 1);
    size_t pos1, len1, pos2, len2;

    if (common == NULL)
        return NULL;  /* failure */

    common[0] = NULL;
    for (pos1 = 0;;) {
        pos1 += strspn(str1 + pos1, " ");
        if (str1[pos1] == '\0')
            break;
        len1 = strcspn(str1 + pos1, " ");
        for (pos2 = 0;;) {
            pos2 += strspn(str2 + pos2, " ");
            if (str2[pos2] == '\0')
                break;
            len2 = strcspn(str2 + pos2, " ");
            if (len1 == len2 && !memcmp(str1 + pos1, str2 + pos2, len1)) {
                char *w = calloc(sizeof(*w), len1 + 1);
                if (w == NULL) {
                    freeWords(common);
                    return NULL;
                }                        
                char **p = realloc(common, sizeof(*p) * (n + 2));
                if (!p) {
                    free(w);
                    freeWords(common);
                    return NULL;
                }
                common = p;
                memcpy(w, str1 + pos1, len1);
                common[n++] = w;
                common[n] = NULL;
                break;
            }
            pos2 += len2;
        }
        pos1 += len1;
    }
    return common;
}

int main(void) {
    const char *name1 = "abc def ghi";
    const char *name2 = "ghi abc jkl";
    char **common = commonWords(name1, name2);
    if (common) {
        for (size_t i = 0; common[i] != NULL; i++) {
            printf("%s\n", common[i]);
        }
        freeWords(common);
    }
    return 0;
}

【讨论】:

  • 如果p 有效,则if (!p || !w) { 语句中的错误处理将中断,因为此时freeWords(common) 将是UB。此外,您可以在分配失败发生之前返回部分常用词列表,而不是释放所有内容并返回NULL。比如:if (p) common = p; if (!p || !w) { free(w); return common; }
  • @IanAbbott:很好!错误处理是如此痛苦,尤其是使用realloc 容易出错的API。我修改了函数以返回分配的数组,除非内存分配失败。
猜你喜欢
  • 2014-12-27
  • 1970-01-01
  • 1970-01-01
  • 2013-10-06
  • 1970-01-01
  • 2018-10-24
  • 1970-01-01
  • 1970-01-01
  • 2013-09-27
相关资源
最近更新 更多