我想做什么?
我正在尝试将内存分配给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);
?
答案 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
如果您有其他问题或需要,请与我们联系。
注意:如果您需要id
和name
的数组,那么您需要一个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
如果您还有其他问题,请与我们联系。