将内存分配给声明为C中结构成员的2d数组?

时间:2016-01-18 03:06:52

标签: c

我想做什么?

我正在尝试将内存分配给char类型二维数组,该数组被声明为结构的成员。

有什么问题?

我不知道该怎么做。

我的代码:

  # include <stdio.h>
  # include <stdlib.h>
  # include <conio.h>

  typedef struct information {
       int id ;
       char **name ;
  } info ;

  void main () {
       info s1 ;
       int i , size ;
       printf ("\n Enter max size of students name : ") ;
       scanf ("%d",&size) ;
       s1.name = ( char** ) malloc ( size * sizeof ( char* ) ) ;
       for ( i = 0 ; i < size ; i++ )
            s1.name [ i ] = ( char** ) malloc ( size * sizeof ( char* ) ) ;
       printf ("\n Enter Id : ") ;
       scanf ("%d",&s1.id) ;
       printf ("\n Enter Name : ") ;
       scanf ("%s",s1.name) ;
       getche () ;
  }

这是对的吗?我是否正确分配了它?

我还想知道为什么在以字符串形式获取输入时我们不使用&。例如,在我的底线第三个代码中,为什么我不能写这个:scanf ("%s",&s1.name);

1 个答案:

答案 0 :(得分:2)

如注释中所述,如果指针不是结构的成员,则将分配/释放完全相同的内容。虽然看起来你不需要char **name指针到指针指向指针),除非一个id与许多names相关联。只需声明一个指向名称的指针(例如char *name;)就足以提供与id一对一关系。

将这些部分组合在一起,并调整scanf格式说明符,以便在读取size后读取/放弃尾随换行符,您可以执行以下操作:

# include <stdio.h>
# include <stdlib.h>
// # include <conio.h>

typedef struct information {
    int id ;
    char *name ;
} info ;

int main (void) {

    info s1;
    int size;

    printf ("\n Enter max size of students name : ");
    scanf ("%d",&size);

    s1.name = malloc (size * sizeof *s1.name);

    printf ("\n Enter Id : ");
    scanf ("%d%*c", &s1.id);

    printf ("\n Enter Name : ");
    scanf ("%[^\n]%*c", s1.name);

    printf ("\n You entered, id: %d, name: %s\n\n", s1.id, s1.name);

    free (s1.name);

    // getche () ;
    return 0;
}

示例使用/输出

$ ./bin/struct_stdnm

 Enter max size of students name : 29

 Enter Id : 231

 Enter Name : Alfred Q. Myres

 You entered, id: 231, name: Alfred Q. Myres

如果您有其他问题或需要,请与我们联系。

注意:如果您需要idname的数组,那么您需要一个struct information数组,而不是 double指针name - 如果我解释你正在做什么有意义的话。

防止输入超出分配

如下面的评论中所述,scanf不是阅读s1.name的最佳选择,因为它不允许变量的最大字段宽度。为了在分配结束后正确防止写作,您应该使用fgets并将您的阅读限制为size

printf ("\n Enter Name : ");
fgets (s1.name, size, stdin);

示例

$ ./bin/struct_stdnm

 Enter max size of students name : 5

 Enter Id : 123

 Enter Name : Johnny Jones

 You entered, id: 123, name: John

所有分配都需要验证&amp;输入

无论您是坚持scanf输入还是使用fgets,您都必须验证所有分配和输入,以确保您实际分配您打算使用的内存,你真的读过你认为你读过的东西。想想这只是代码的另一层完整性。虽然在没有完全验证的情况下学习使用示例可能会很方便,但在为所有分配和输入提供足够的检查之前,不应该考虑代码完成。这是一个更新,显示对您的代码的最小验证检查:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// # include <conio.h>

typedef struct information {
    int id ;
    char *name ;
} info ;

int main (void) {

    info s1;
    int size;
    size_t len;

    printf ("\n Enter max size of students name : ");
    if (scanf ("%d",&size) != 1) { /* validate converison */
        fprintf (stderr, "error: conversion of size failed.\n");
        return 1;
    }
    if (size < 1) { /* validate size */
        fprintf (stderr, "error: invalid size entered.\n");
        return 1;
    }

    /* always validate allocations */
    if (!(s1.name = malloc (size * sizeof *s1.name))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

    printf ("\n Enter Id : ");
    if (scanf ("%d%*c", &s1.id) != 1) { /* validate converison */
        fprintf (stderr, "error: conversion of size failed.\n");
        return 1;
    }

    printf ("\n Enter Name : ");
    if (fgets (s1.name, size, stdin)) {
        len = strlen (s1.name);

        /* validate all characters fit within 'size' allocation */
        if (len + 1 == (size_t)size && (s1.name)[len-1] != '\n')
            printf (" warning: name exceeded allocation.\n");

        /* remove trailing newline from name */
        if (len && (s1.name)[len-1] == '\n')
            (s1.name)[--len] = 0;
    }
    else {
        fprintf (stderr, "error: name entry failed.\n");
        return 1;
    }

    printf ("\n You entered, id: %d, name: %s\n\n", s1.id, s1.name);

    free (s1.name);

    // getche () ;
    return 0;
}

如果您没有分配足够的空间来保存输入的整个名称,这也会标记:

短分配示例

$ ./bin/struct_stdnm

 Enter max size of students name : 5

 Enter Id : 123

 Enter Name : Johnny Jones
 warning: name exceeded allocation.

 You entered, id: 123, name: John

如果您还有其他问题,请与我们联系。