【问题标题】:Can I convert char*[20] to char[][20]?我可以将 char*[20] 转换为 char[][20] 吗?
【发布时间】:2018-05-09 03:40:45
【问题描述】:

我现在自己更正了程序。 这仍然是-Never-回答的问题: 我有一个二维字符数组,每个数组都包含一个单词。我使用函数将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;
        }
    }
}

然后我会调用一个函数来测试和打印二维数组中的单词(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[][] 不起作用。当然不是。我什至不在源代码中使用它。那只是问题的标题。请在任何其他答案之前阅读所有内容。

【问题讨论】:

  • 您的 fix-my-code 问题在这里是题外话。您需要发布minimal reproducible example
  • 您的代码非常混乱,正如其他人指出的那样,充满了未定义的行为。您可能已经成功地让编译器接受了某些东西,但这并不意味着它会像您认为的那样远程执行任何操作。
  • 版主说明:请进行扩展讨论以进行聊天。评论不是他们的地方。

标签: c pointers multidimensional-array c-strings


【解决方案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;
}

我警告你,这是一个糟糕的设计,会给你带来无穷无尽的问题。这是非常错误的方法。

这里不需要释放任何东西,因为它都是静态分配的。

【讨论】:

  • 我的版本可以在没有库的情况下使用,并且可以与动态/静态分配的数组一起使用,非常像库一样感谢您的版本,我很感激
  • @PrometeoPrime 这是我最后一次参与回答像你这样的人的问题。你这里的版本根本不起作用。静态数据在那里是因为工作程序需要数据才能使用。
  • @PrometeoPrime 你对每个人来说都太聪明了,任何人都不可能回答你的问题让你满意。这是对一群非常有能力的人时间的巨大浪费。
  • 没关系,我认为如果有人知道正确的答案,他会发布但没有,在你回答问题之前回答的人一开始就错了,他们也浪费时间解释如何数组需要有一个固定的大小,这不是我的问题,这是他们的时间
  • 不管怎样,我没那么聪明,我相信只要你练习得够多,任何人都可以使用指针
【解决方案2】:

我有一个二维数组

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

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

(而且你的代码和你无数的cmets,说明你很迷茫。没关系,编程难学;需要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标准。为此目的分配一周的密集工作(在此期间根本不要接触您的代码;也许对与您的项目无关的玩具代码进行一些 tiny 实验,并使用调试器来了解什么正在计算机中进行)。

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

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

你可以编码extern char array[][16];,但这太令人困惑了,我弄错了——因为我从不那样做——你真的应该从不这样编码.

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

根据经验:从不在 C 中使用所谓的“二维数组”(实际上是数组的数组)。如果您需要可变维度的矩阵(并且您可能不需要)实现它们作为抽象数据类型,例如 here

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

struct mydata_st {
  char bytes[16];
};

它更具可读性。

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

您可能应该完全开始您的代码(并丢弃您的代码)并以abstract data types 的方式思考。我强烈推荐阅读SICP(可免费下载)。因此,首先,使用英语或意大利语等自然语言在纸上写下规范(操作的完整列表,或库的接口或 API)。

也许您想要某种字符串向量或字符矩阵(我不明白您想要什么,而且您可能在纸上没有足够清楚地指定它)。

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

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

所以也许你想要某种动态向量动态分配类型。然后首先定义对它们的确切操作列表。阅读flexible array members 上的维基页面。它可能非常有用。


顺便说一句,使用所有警告和调试信息进行编译,因此请使用 gcc -Wall -Wextra -g 编译您的 C 代码(如果使用 GCC)。 使用调试器gdb更好地了解你的程序在你的系统上的行为,一步一步运行它,查询被调试的process的状态。

使用 C++11 或更高版本编码

如果使用 C++11(与 C99 不同的语言)编码,请使用现有的 typescontainers。再次,阅读一些好书(如this)更多文档和reference。 C++ 是一种非常难的编程语言,因此请花 数周 来阅读。

【讨论】:

【解决方案3】:

不,你不能。那是因为char[][]incomplete type 的数组,因此是invalid(所以它根本不存在)。数组元素必须是完整的类型,即类型的大小、对齐方式和布局必须在编译时确定。

请停止争论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[][],因为指针数组转换只能在顶层完成,即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() 只是标准方式,应该没问题。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
  • 2012-07-16
  • 2013-01-10
  • 1970-01-01
  • 2019-12-15
相关资源
最近更新 更多