我可以将char * [20]转换为char [] [20]吗?

时间:2017-11-25 10:23:16

标签: c pointers multidimensional-array c-strings

我现在已经自己纠正了这个程序。 这仍然是 - 否则回答的问题: 我有一个二维数组的字符,每个数组都包含一个字。我将一个char*字逐字地分成一个函数,将它们放在数组中。我的问题是它不打印单词而是随机字符。可能是指针问题?我不确定char*[20]char[][20]的转换 因为我希望将char*spamArray[20]过滤为char[][20]

我需要将char*[20]传递给具有参数char[][20]的过滤器。

这是电话:

char* spam = "this is a string";
//spam isn't actually initialized this way, but this is just for explaining what it contains

//OLD QUESTION CODE:char (*spamArray)[20]  = (char(*)[20])malloc((sizeof(char) * 20) * nSpam);
//new:
char spamArray[nSpam][20];
//nSpam is the number of words

splitstring(spam, &spamArray[0], nSpam);

这是函数splitstring到单词

inline void splitstring(char *str, char (*arr)[20], size_t t)
{
    size_t i = 0;   //index char nella stringa dell'array
    while(t != 0)
    {
        if (*str != ' ' && *str != '\0')
        {
            (*arr)[i] = *str;
            *str++;
            i++;
        }
        else
        {
            t--;
            *str++;
            (*arr)[i] = '\0';
            *arr++;
            i = 0;
        }
    }
}

然后我将调用一个函数来测试和打印2D数组中的单词(spamArray)

filter_mail(&txt, spamArray) //i call the function this way

void filter_mail(char **line, char spam[][20], int nSpam)
{
    char *line_tmp = *line;
    bool isSpam = 0;

    int a = 0;
    int c = 0;

    while(nSpam!= 0)
    {
        if (spam[a][c] != '\0')
        {
            printf("%c", spam[a][c]);
            c++;
        }
        else
        {
            a++;
            c = 0;
            nSpam--;
        }
    }
}

然后每次打印随机的东西,程序崩溃。 另外,我应该如何释放spamArray? 以这种方式释放它是否正确?

free(spamArray)

我现在没有得到任何答案,因为每个人都指出使用char[][]不起作用。当然,它没有。我甚至没有在源代码中使用它。这只是问题的标题。请在任何其他答案之前阅读所有内容。

3 个答案:

答案 0 :(得分:3)

  

我有一个2D数组

不,你不是。在C99或C11 2D数组不存在,并且不存在于C++11中。顺便说一句,即使C++17在C ++ 11和C ++ 14标准中添加了更多容器,它们也没有添加矩阵。

数组(在C和C ++中) 总是单维。在一些奇怪的情况下,你可以有数组的数组(每个组件应该具有相同的类型,所以相同的尺寸,相同的大小,相同的对齐),但这是令人困惑的,你甚至不应该尝试。

(你的代码和你的众多评论表明你很困惑。没关系,编程很难学;你需要years of work

  

我可以将char * []转换为char [] []吗?

,因为 char[][]类型不存在且不存在(在C ++ 11或C ++ 14以及C99或C11中都存在) )因为数组应该具有相同固定和已知大小和类型的元素。

查看现有的库(例如Glib),至少是为了获取灵感。研究相关free software项目的源代码(例如,在github上)。

谨防undefined behavior ;可能会发生代码(如您的代码)错误但没有正常崩溃。是UB的scared

  

然后每次打印随机的东西,程序崩溃

UB的典型案例(代码中可能其他)。你很幸运能看到崩溃。有时UB更加阴险。

在C99或C11中编码

首先,花更多时间阅读文档。先读几本书。然后看一些reference site。最后,仔细阅读C11的n1570标准。为此目的分配一周密集的工作(并且在此期间根本不要触摸您的代码;也许在与您的项目无关的玩具代码上进行一些微小的实验,并使用调试器了解计算机中发生的事情。)

您可能有一个16字节宽的字符串数组;我经常不这样做,但如果我这样做,我更喜欢命名中间类型:

 typedef char sixteenbytes_ty[16];
 extern sixteenbytes_ty array[];

您可能会编码extern char array[][16];,但这太令人困惑了,我弄错了 - 因为我从不那样做 - 而且你真的应该从不代码。

这声明了一个包含16字节数组元素的全局array。同样,我不建议这样做。

根据经验,从不使用所谓的" 2D数组" (实际上是数组中的数组)如果你需要可变维度的矩阵(你可能不会)将它们实现为像here这样的抽象数据类型。

如果您操作恰好有16个字节的数据,请创建struct个数据:

struct mydata_st {
  char bytes[16];
};

它更具可读性。

你可能有一个指针数组,例如char*[](每个指针在我的Linux / x86-64机器上有一个固定的大小,8个字节,与它所指向的内存区域的分配大小不同)。

您可能应该完全启动代码(并丢弃代码)并根据abstract data types进行思考。我强烈建议阅读SICP(免费下载)。首先,使用英语或意大利语等自然语言在纸上写下规范(操作的完整列表,或库的接口或API)。

也许你想要某种字符串矢量或字符矩阵(我不理解你想要的东西,你可能没有在纸上清楚地说明它。)

如果在C99中编码,请考虑在某些(内部)类型实现中使用一些灵活的数组成员。

也许您决定处理一些动态分配的字符串数组(每个字符串都由strdupasprintf等获得...)。

所以也许你想要一些动态分配类型的动态矢量。然后首先定义它们的确切操作列表。阅读flexible array members上的wikipage。它可能非常有用。

BTW,编译所有警告和调试信息,因此请使用gcc -Wall -Wextra -g C代码进行编译(如果使用GCC)。 使用调试器gdb 更好地了解程序在系统中的行为,逐步运行,查询已调试process的状态。

在C ++ 11或更新版本中编码

如果使用现有的typescontainers在C ++ 11中编码(与C99相同的语言)。再次,阅读一些好书(如this)更多文档和reference。 C ++是一种非常困难的编程语言,所以花费几个星期阅读。

答案 1 :(得分:1)

不,你不能。这是因为char[][]incomplete type的数组,因此无效(因此它根本不存在)。数组元素必须是完整类型,也就是说,必须在编译时确定类型的大小,对齐方式和布局。

请停止争论char[][]的存在。我完全可以向你保证it doesn't exist

go Google

固定长度数组是候选解决方案:

char[][32]

但动态内存分配(使用指针数组)更好,因为分配的内存大小可灵活更改。然后你可以声明如下函数:

void filter_mail(char **line, char spam**);

as suggested。至少,你应该这样做#(但你不能省略m):

void foo(size_t m, char (*)[m]);

您可以 从不 声明char[][],因为指针数组转换只能 在顶级< / strong>,即char*[]char[][](这是因为operator precedence)。

我打赌你根本不知道你在splitstring()

做了什么
while(t != 0)
{
    if (*str != ' ' && *str != '\0')
    {
        *arr[c] = *str;
        *str++;
        c++;
    }
    else
    {
        t--;
        *str++;
        *arr[c] = '\0';
        *arr++;
        c = 0;
    }
}

由于*arr[c]等同于arr[c][0],您只需str复制到arr 的每个字符串中的第一个元素。获取括号,使其看起来像(*arr)[c]。然后在指针递增之前删除星号(您根本不使用取消引用的值):

while(t != 0)
{
    if (*str != ' ' && *str != '\0')
    {
        (*arr)[c] = *str;
        str++;
        c++;
    }
    else
    {
        t--;
        str++;
        (*arr)[c] = '\0';
        arr++;
        c = 0;
    }

现在应该没事了。

最后,don't cast the result of malloc。释放spamArray  使用free()只是标准方式,应该没问题。

答案 2 :(得分:1)

这是一个程序,它是您的程序版本,可以执行您似乎想要执行的操作:

#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <stdio.h>

const int nSpam = 30;

char* spam = "this is a string";

char spamArray[30][20];
//nSpam is the number of words

void splitstring(char *str, char arr[][20], size_t nSpam)
{
   int word_num = 0;
   int char_num = 0;
   int inspace = 0;
   for (char *i = str; *i != '\0'; ++i)
   {
      if (!isspace(*i))
      {
         inspace = 0;
         assert(word_num < nSpam);
         arr[word_num][char_num++] = *i;
         assert(char_num < 20);
      }
      else
      {
         if (!inspace)
         {
            arr[word_num++][char_num] = '\0';
            char_num = 0;
            inspace = 1;
         }
      }
   }
   if (!inspace)
   {
      arr[word_num++][char_num] = '\0';
   }
   while (word_num < nSpam)
   {
      arr[word_num++][0] = '\0';
   }
}

void filter_mail(char const * const *line, char spam[][20], size_t nSpam)
{
    int a = 0;

    while (a < nSpam)
    {
       int c = 0;
       while (spam[a][c] != '\0')
       {
          printf("%c", spam[a][c++]);
       }
       printf("\n");
       ++a;
    }
}

char const * const mail_msg[] = {
   "This is a line.\n",
   "This is another line.\n",
   0
};

int main()
{
   splitstring(spam, spamArray, 30);
   filter_mail(mail_msg, spamArray, 30);
   return 0;
}

我警告你,这是一个糟糕的设计,会导致你无法解决问题。这是非常错误的方法。

没有必要在这里释放任何东西,因为它们都是静态分配的。