我正在为我的CS1课程开发一个项目,我遇到了一些我以前从未想过的东西。我知道C中的所有数组本质上都是指向数组第一个元素的指针,而字符串实际上只是一个字符数组。但是,对于我的任务,我们必须读入一个文件,部分文件如下:
Brad Tim Rick (more man names separated by spaces) Lucy Angela Tina (more women names separated by spaces)
这是一个简短的例子,但我要做的是提取名称并将它们存储到两个单独的数组中,一个用于男性,一个用于女性。
我从未使用过类似的东西,所以我当然很困惑。这就是我想要做的,当然它不起作用......哦是的,我正试图将它们存储在动态分配中。唯一的规范是名称永远不会超过19个字符(我应该说二十个允许字符串末尾的'/ 0'无论如何仍然存在?)我怎么能告诉编译器,“嘿我想要一个字符串数组,每个字符串可以容纳19个字符+ 1用于“字符串预告片'/ 0'”?然后我如何通过指针访问它们?
char **mens_names, **womens_names;
mens_names = malloc(number_of_couples * sizeof(char[19]));
womens_names = malloc(number_of_couples * sizeof(char[19]));
if(mens_names == NULL){
printf("Malloc failed! Memory could not be allocated to variable mens_names.");
return -1;
}
int i;
for(i = 0; i < number_of_couples; i++){
fscanf(input_file, "%s", &mens_names[i]);
}
if(womens_names == NULL){
printf("Malloc failed! Memory could not be allocated to variable womens_names.");
return -1;
}
for(i = 0; i < number_of_couples; i++){
fscanf(input_file, "%s", &womens_names[i]);
}
for(i = 0; i < number_of_couples; i++){
printf("Man: %s ", mens_names[i]);
printf("Woman: %s\n", womens_names[i]);
}
答案 0 :(得分:2)
您正在谈论2D数组,但仅将其初始化为一维数组。二维数组(矩阵)的正确初始化如下:
static char** allocate_matrix(int nrows, int ncols)
{
int i;
char **matrix;
/* allocate array of pointers */
matrix = malloc( nrows*sizeof(char*));
if(matrix==NULL)
return NULL; /* Allocation failed */
/* Allocate column for each name */
for(i = 0; i < nrows; i++)
matrix[i] = malloc( ncols*sizeof(char));
if(matrix[i-1] == NULL)
return NULL; /* Allocation failed */
return matrix;
}
在 main():
中<...>
mens_names = allocate_matrix(number_of_couples, 19);
womens_names = allocate_matrix(number_of_couples, 19);
<...>
/* Of course, do not forget to free memory once you are done */
答案 1 :(得分:2)
我知道C中的所有数组本质上都是指向数组第一个元素的指针
不完全。数组和指针完全是两个不同的东西。除非它是sizeof
,_Alignof
或一元&
运算符的操作数,或者是用于在声明中初始化数组的字符串文字,表达式<类型为“{元素数组T
”的/ em>将被转换为类型为“指向T
的指针”的表达式,其值将是数组中的第一个元素。
鉴于声明
int a[10];
a
指定的对象总是永远是int
的10元素数组;但是,表达式 a
可以被视为指向第一个元素的指针。
如果你知道你的字符串永远不会超过19个字符(20个元素,包括终结符),但不知道提前字符串的数量,你可以做这样的事情:
char (*mens_names)[20];
char (*womens_names)[20];
...
mens_names = malloc(number_of_couples * sizeof *mens_names);
womens_names = malloc(number_of_couples * sizeof *womens_names);
...
fscanf(input_file, "%s", mens_names[i]);
...
free(mens_names);
free(womens_names);
在这种情况下,我们已将mens_names
和womens_names
声明为指向char
的20个元素数组的指针(括号内容)。因此,sizeof *mens_names
相当于sizeof (char [20])
。
您可以像使用常规二维数组一样访问每个角色:
char x = mens_names[i][j];
mens_names[i]
隐式取消引用mens_names
指针(请记住表达式a[i]
被解释为*(a + i)
)。
这种方法比KBart的方法有一些优势。首先,所有内存都作为单个块连续分配,如果缓存成为问题,这可能很重要。其次,每个数组只需要一个malloc
和一个free
。当然,这假设每个名称数组的最大大小是a)固定的,b)在编译时是已知的。
如果您在运行时之前不知道名称的大小,并且您使用的是C99编译器或支持可变长度数组的C2011编译器,则可以执行以下操作:
size_t name_len, number_of_couples;
// get name_len from the user or input file
// get number_of_couples
char (*mens_names)[name_len+1] = malloc(number_of_couples * sizeof *mens_names);
...
如果您在运行时之前不知道名称的大小,并且您正在使用不支持VLA的编译器,那么您将需要使用KBart的方法。
如果你想让真正花哨,你可以使用一个三维数组而不是两个二维数组:
#define MENS_NAMES 0
#define WOMENS_NAMES 1
...
char (*all_names)[2][20] = malloc(number_of_couples * sizeof *all_names);
...
fscanf(input_file, "%s", all_names[i][MENS_NAMES]);
...
free(all_names);
答案 2 :(得分:0)
void init(char**** tab,int size1d,int size2d,int size_string)
{
int iterator;
int iterator_2;
char*** temp = (char***) calloc(size1d,sizeof(char**));
for (iterator = 0 ; iterator < size1d;iterator++)
{
*(temp+iterator) = (char**) calloc(size2d,sizeof(char*));
for (iterator_2 = 0;iterator_2 < size2d;iterator_2++)
{
*(*(temp+iterator)+iterator_2) = (char*) calloc(size_string,sizeof(char));
}
}
*tab = temp;
}
int main()
{
char*** tab;
init(&tab,100,100,255);
tab[5][99] = "Hi";
printf("%s",tab[5][99]);
}