用C语言制作二维数组字符串

时间:2013-01-29 12:41:31

标签: c arrays character

我正在为我的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]);
}

3 个答案:

答案 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_nameswomens_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]);
}