I am working on a project for my CS1 class and I have run into something I have never thought of before. I know at all arrays in C are essentially pointer to the first element of an array, and a string is really just a character array. However, for my assignment we have to read in a file, and part of the file is the following:
我正在为我的CS1课程开发一个项目,我遇到了一些我以前从未想过的东西。我知道C中的所有数组本质上都是指向数组第一个元素的指针,而字符串实际上只是一个字符数组。但是,对于我的任务,我们必须读入一个文件,部分文件如下:
Brad Tim Rick (more man names separated by spaces) Lucy Angela Tina (more women names separated by spaces)
This is a short example, but what I have to do is extract the names and store them into two separate arrays, one for men and one for females.
这是一个简短的例子,但我要做的是提取名称并将它们存储到两个单独的数组中,一个用于男性,一个用于女性。
I have never worked with something like this, so of course I am confused. This is what I am trying to do, and of course its not working... oh yeah, and I'm trying to store them in dynamic allocation. The only spec says that the names will never exceed 19 characters (should I say twenty to allow the '/0' at the end of the string to still be there no matter what?) How can I tell the compiler, "hey I want an array of strings, and each string can hold 19 characters + 1 for the "string trailer '/0' "? And then how do I access those through pointers?
我从未使用过这样的东西,所以我当然很困惑。这就是我想要做的,当然它不起作用......哦是的,我正试图将它们存储在动态分配中。唯一的规格说名称永远不会超过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]);
}
3 个解决方案
#1
2
I know at all arrays in C are essentially pointer to the first element of an array
我知道C中的所有数组本质上都是指向数组第一个元素的指针
Not quite. Arrays and pointers are two different things entirely. Except when it is the operand of the sizeof
, _Alignof
, or unary &
operator, or is a string literal being used to initialize an array in a declaration, an expression of type "N-element array of T
" will be converted to an expression of type "pointer to T
" and its value will be the address of the first element in the array.
不完全的。数组和指针完全是两个不同的东西。除非它是sizeof,_Alignof或一元&运算符的操作数,或者是用于在声明中初始化数组的字符串文字,否则“N元素数组T”的表达式将转换为表达式类型为“指向T的指针”及其值将是数组中第一个元素的地址。
Given the declaration
鉴于声明
int a[10];
the object that a
designates is always and forever a 10-element array of int
; however, the expression a
may be treated as a pointer to the first element.
指定的对象始终是永远的10元素int数组;但是,表达式a可以被视为指向第一个元素的指针。
If you know your strings will never be more than 19 characters long (20 elements including the terminator), but don't know the number of strings ahead of time, you can do something like this:
如果你知道你的字符串永远不会超过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);
In this case, we've declared mens_names
and womens_names
as pointers to 20-element arrays of char
(the parentheses matter). Thus, sizeof *mens_names
is equivalent to sizeof (char [20])
.
在这种情况下,我们已经将mens_names和womens_names声明为指向20个元素的char数组(括号内容)。因此,sizeof * mens_names等于sizeof(char [20])。
You would access each individual character as you would with a regular 2-d array:
您可以像使用常规二维数组一样访问每个单独的字符:
char x = mens_names[i][j];
mens_names[i]
implicitly dereferences the mens_names
pointer (remember that the expression a[i]
is interpreted as *(a + i)
).
mens_names [i]隐式取消引用mens_names指针(记住表达式a [i]被解释为*(a + i))。
This method has a couple of advantages over KBart's method. First, all the memory is allocated contiguously as a single chunk, which may matter if caching becomes an issue. Secondly, you only need one malloc
and one free
for each array. Of course, this assumes that the maximum size of each name array is a) fixed and b) known at compile time.
这种方法比KBart方法有一些优点。首先,所有内存都作为单个块连续分配,如果缓存成为问题,这可能很重要。其次,每个数组只需要一个malloc和一个free。当然,这假设每个名称数组的最大大小是a)固定的,b)在编译时是已知的。
If you won't know the size of the name until runtime, and you're using a C99 compiler or a C2011 compiler that supports variable-length arrays, you can do something like this:
如果您在运行时之前不知道名称的大小,并且您使用的是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);
...
If you won't know the size of the name until runtime, and you're using a compiler that doesn't support VLAs, then you'll need to use KBart's method.
如果在运行时之前您不知道名称的大小,并且您使用的是不支持VLA的编译器,那么您将需要使用KBart的方法。
If you wanted to get really fancy, you could use a single 3-dimensional array instead of two 2-dimensional arrays:
如果你想变得非常花哨,你可以使用一个三维数组而不是两个二维数组:
#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
2
You are talking about 2D array, but initializing it only as a one dimensional array. The correct initialization of 2D array (matrix) is as follows:
您正在谈论2D数组,但仅将其初始化为一维数组。 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;
}
In your 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 */
#3
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]);
}
#1
2
I know at all arrays in C are essentially pointer to the first element of an array
我知道C中的所有数组本质上都是指向数组第一个元素的指针
Not quite. Arrays and pointers are two different things entirely. Except when it is the operand of the sizeof
, _Alignof
, or unary &
operator, or is a string literal being used to initialize an array in a declaration, an expression of type "N-element array of T
" will be converted to an expression of type "pointer to T
" and its value will be the address of the first element in the array.
不完全的。数组和指针完全是两个不同的东西。除非它是sizeof,_Alignof或一元&运算符的操作数,或者是用于在声明中初始化数组的字符串文字,否则“N元素数组T”的表达式将转换为表达式类型为“指向T的指针”及其值将是数组中第一个元素的地址。
Given the declaration
鉴于声明
int a[10];
the object that a
designates is always and forever a 10-element array of int
; however, the expression a
may be treated as a pointer to the first element.
指定的对象始终是永远的10元素int数组;但是,表达式a可以被视为指向第一个元素的指针。
If you know your strings will never be more than 19 characters long (20 elements including the terminator), but don't know the number of strings ahead of time, you can do something like this:
如果你知道你的字符串永远不会超过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);
In this case, we've declared mens_names
and womens_names
as pointers to 20-element arrays of char
(the parentheses matter). Thus, sizeof *mens_names
is equivalent to sizeof (char [20])
.
在这种情况下,我们已经将mens_names和womens_names声明为指向20个元素的char数组(括号内容)。因此,sizeof * mens_names等于sizeof(char [20])。
You would access each individual character as you would with a regular 2-d array:
您可以像使用常规二维数组一样访问每个单独的字符:
char x = mens_names[i][j];
mens_names[i]
implicitly dereferences the mens_names
pointer (remember that the expression a[i]
is interpreted as *(a + i)
).
mens_names [i]隐式取消引用mens_names指针(记住表达式a [i]被解释为*(a + i))。
This method has a couple of advantages over KBart's method. First, all the memory is allocated contiguously as a single chunk, which may matter if caching becomes an issue. Secondly, you only need one malloc
and one free
for each array. Of course, this assumes that the maximum size of each name array is a) fixed and b) known at compile time.
这种方法比KBart方法有一些优点。首先,所有内存都作为单个块连续分配,如果缓存成为问题,这可能很重要。其次,每个数组只需要一个malloc和一个free。当然,这假设每个名称数组的最大大小是a)固定的,b)在编译时是已知的。
If you won't know the size of the name until runtime, and you're using a C99 compiler or a C2011 compiler that supports variable-length arrays, you can do something like this:
如果您在运行时之前不知道名称的大小,并且您使用的是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);
...
If you won't know the size of the name until runtime, and you're using a compiler that doesn't support VLAs, then you'll need to use KBart's method.
如果在运行时之前您不知道名称的大小,并且您使用的是不支持VLA的编译器,那么您将需要使用KBart的方法。
If you wanted to get really fancy, you could use a single 3-dimensional array instead of two 2-dimensional arrays:
如果你想变得非常花哨,你可以使用一个三维数组而不是两个二维数组:
#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
2
You are talking about 2D array, but initializing it only as a one dimensional array. The correct initialization of 2D array (matrix) is as follows:
您正在谈论2D数组,但仅将其初始化为一维数组。 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;
}
In your 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 */
#3
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]);
}