我现在已经自己纠正了这个程序。
这仍然是 - 否则回答的问题:
我有一个二维数组的字符,每个数组都包含一个字。我将一个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[][]
不起作用。当然,它没有。我甚至没有在源代码中使用它。这只是问题的标题。请在任何其他答案之前阅读所有内容。
答案 0 :(得分:3)
不,你不是。在C99或C11中 2D数组不存在,并且不存在于C++11中。顺便说一句,即使C++17在C ++ 11和C ++ 14标准中添加了更多容器,它们也没有添加矩阵。我有一个2D数组
数组(在C和C ++中) 总是单维。在一些奇怪的情况下,你可以有数组的数组(每个组件应该具有相同的类型,所以相同的尺寸,相同的大小,相同的对齐),但这是令人困惑的,你甚至不应该尝试。
(你的代码和你的众多评论表明你很困惑。没关系,编程很难学;你需要years of work)
我可以将char * []转换为char [] []吗?
否,因为 char[][]
类型不存在且不存在(在C ++ 11或C ++ 14以及C99或C11中都存在) )因为数组应该具有相同固定和已知大小和类型的元素。
查看现有的库(例如Glib),至少是为了获取灵感。研究相关free software项目的源代码(例如,在github上)。
谨防undefined behavior ;可能会发生代码(如您的代码)错误但没有正常崩溃。是UB的scared!
然后每次打印随机的东西,程序崩溃
UB的典型案例(代码中可能其他)。你很幸运能看到崩溃。有时UB更加阴险。
首先,花更多时间阅读文档。先读几本书。然后看一些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中编码,请考虑在某些(内部)类型实现中使用一些灵活的数组成员。
也许您决定处理一些动态分配的字符串数组(每个字符串都由strdup
或asprintf
等获得...)。
所以也许你想要一些动态分配类型的动态矢量。然后首先定义它们的确切操作列表。阅读flexible array members上的wikipage。它可能非常有用。
BTW,编译所有警告和调试信息,因此请使用gcc -Wall -Wextra -g
C代码进行编译(如果使用GCC)。 使用调试器gdb
更好地了解程序在系统中的行为,逐步运行,查询已调试process的状态。
如果使用现有的types和containers在C ++ 11中编码(不与C99相同的语言)。再次,阅读一些好书(如this)更多文档和reference。 C ++是一种非常困难的编程语言,所以花费几个星期阅读。
答案 1 :(得分:1)
char[][]
是incomplete type的数组,因此无效(因此它根本不存在)。数组元素必须是完整类型,也就是说,必须在编译时确定类型的大小,对齐方式和布局。
请停止争论char[][]
的存在。我完全可以向你保证it doesn't exist。
固定长度数组是候选解决方案:
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;
}
我警告你,这是一个糟糕的设计,会导致你无法解决问题。这是非常错误的方法。
没有必要在这里释放任何东西,因为它们都是静态分配的。