英文:
Asking about malloc for (char*)
问题
我只想知道为什么这个部分不需要字符串的长度。
完整的代码(来自互联网的某个地方):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
typedef struct
{
char* firstName;
char* lastName;
int rollNumber;
} STUDENT;
int numStudents = 2;
int x;
STUDENT* students = (STUDENT *)malloc(numStudents * sizeof *students);
for (x = 0; x < numStudents; x++)
{
students[x].firstName = (char*)malloc(sizeof(char*));
printf("Enter first name :");
scanf("%s", students[x].firstName);
students[x].lastName = (char*)malloc(sizeof(char*));
printf("Enter last name :");
scanf("%s", students[x].lastName);
printf("Enter roll number :");
scanf("%d", &students[x].rollNumber);
}
for (x = 0; x < numStudents; x++)
printf("First Name: %s, Last Name: %s, Roll number: %d\n", students[x].firstName, students[x].lastName, students[x].rollNumber);
return (0);
}
解释部分:
students[x].firstName=(char*)malloc(sizeof(char*));
这行代码用于为students[x].firstName
分配内存,但分配的内存大小似乎不正确,因为它使用了sizeof(char*)
,这将分配一个指向字符指针的内存空间,而不是字符串本身的内存空间。应该使用sizeof(char)
来分配一个字符的内存空间,或者更好地使用动态分配以适应输入的字符串长度,以避免内存浪费和缓冲区溢出。
英文:
I just wonder why
students[x].firstName=(char*)malloc(sizeof(char*));
This one doesn't need the length of the string.
Full code (from somewhere on the internet):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
typedef struct
{
char* firstName;
char* lastName;
int rollNumber;
} STUDENT;
int numStudents=2;
int x;
STUDENT* students = (STUDENT *)malloc(numStudents * sizeof *students);
for (x = 0; x < numStudents; x++)
{
students[x].firstName=(char*)malloc(sizeof(char*));
printf("Enter first name :");
scanf("%s",students[x].firstName);
students[x].lastName=(char*)malloc(sizeof(char*));
printf("Enter last name :");
scanf("%s",students[x].lastName);
printf("Enter roll number :");
scanf("%d",&students[x].rollNumber);
}
for (x = 0; x < numStudents; x++)
printf("First Name: %s, Last Name: %s, Roll number: %d\n", students[x].firstName, students[x].lastName, students[x].rollNumber);
return (0);
}
Explained for:
students[x].firstName=(char*)malloc(sizeof(char*));
答案1
得分: 7
根据您使用的平台不同,以下代码行:
students[x].firstName=(char*)malloc(sizeof(char*));
在大多数情况下,等效于:
students[x].firstName = malloc(4);
或者
students[x].firstName = malloc(8);
因为这是大多数平台上 char *
(指向 char
的指针)的大小。
这意味着如果用户输入超过3或7个字符(包括终止的空字符,4或8个字符),那么以下代码行:
printf("Enter first name :");
scanf("%s",students[x].firstName);
将导致缓冲区溢出,这会引发未定义的行为。这意味着您的程序可能会崩溃或以其他方式发生错误。
因此,您的担忧是合理的。这行代码:
students[x].firstName=(char*)malloc(sizeof(char*));
应该指定足以存储用户输入的最大可能长度的大小,而不仅仅是指针的大小(通常为4或8个字节)。
然而,即使您指定了一个更高的值,如:
students[x].firstName = malloc(200);
您的程序仍然不安全,因为用户仍然可以通过输入至少200个字符的单词来引发缓冲区溢出。因此,更安全的做法是:
scanf("%199s", students[x].firstName);
而不是:
scanf("%s",students[x].firstName);
这将限制 scanf
写入内存缓冲区的字符数为200(匹配的199个字符加上终止的空字符)。
然而,即使这个解决方案更好,它仍然不是理想的,因为如果输入太长,scanf
会悄悄截断输入,并将其余部分留在输入流中。这意味着这些剩余的输入可能会在下次调用输入流的 scanf
时引发问题,因为它将首先被读取。
因此,最好的做法是始终读取整行输入,如果输入太长而无法存储在内存缓冲区中,则拒绝输入并提示用户输入新的内容。
以下是使用 fgets
而不是 scanf
的示例代码,因为 fgets
更适合读取整行输入。但是,由于使用 fgets
也不太容易,我创建了两个自己的辅助函数来使用 fgets
,这些函数称为 get_line_from_user
和 get_int_from_user
。这些是我从 main
中调用的两个函数。我不直接从 main
中调用 fgets
。
// 在上述提供的代码中的示例程序中
此程序具有以下行为:
Enter first name: This line is longer than 200 characters. This line is longer than 200 characters. This line is longer than 200 characters. This line is longer than 200 characters. This line is longer than 200 characters.
Input was too long to fit in buffer!
Enter first name: John
Enter last name: Doe
Enter roll number: 8
Enter first name: Jane
Enter last name: Doe
Enter roll number: 9
First Name: John, Last Name: Doe, Roll number: 8
First Name: Jane, Last Name: Doe, Roll number: 9
请注意,通常建议始终检查 malloc
的返回值,因为如果由于某种原因 malloc
失败,那么程序将会出现问题。我没有将这些检查添加到我的代码中,因为我不想分散其他我所做的更改的注意力。
英文:
Depending on which platform you are using, the line
students[x].firstName=(char*)malloc(sizeof(char*));
is most likely equivalent to either
students[x].firstName = malloc( 4 );
or
students[x].firstName = malloc( 8 );
because that is the size of a char *
(pointer to char
) on most platforms.
This means that if the user input is more than 3 or 7 characters (4 or 8 including the terminating null character), then the lines
printf("Enter first name :");
scanf("%s",students[x].firstName);
will cause a buffer overflow, which will invoke undefined behavior. This means that your program could crash or misbehave in some other way.
Therefore, your concerns are valid. The line
students[x].firstName=(char*)malloc(sizeof(char*));
should instead specify a size that is sufficient to store the maximum possible length of the user input, instead of only the size of a pointer (which is 4 or 8 bytes).
However, even if you specify a much higher value instead, such as
students[x].firstName = malloc( 200 );
then your program still is not safe, because the user could still cause a buffer overflow by entering a word with a length of at least 200 characters. Therefore, it would be safer to write
scanf( "%199s", students[x].firstName );
instead of:
scanf("%s",students[x].firstName);
This will limit the number of characters written to the memory buffer by scanf
to 200 (199 matched characters plus the terminating null character).
However, even if this solution is better, it still is not ideal, because scanf
will silently truncate the input, if it is too long, and will leave the rest of the line on the input stream. This means that this left-over input will likely cause trouble the next time you call scanf
on the input stream, because that is what will be read first.
For this reason, it would be better to always read an entire line of input, and if it is too long to be stored in the memory buffer, to reject the input with an error message and to prompt the user for new input.
In the code below is an example that uses fgets
instead of scanf
, because fgets
is better suited for reading whole lines of input. However, since using fgets
is also not that easy, I am using fgets
in two helper functions that I created myself. I call these functions get_line_from_user
and get_int_from_user
. Those are the two functions that I call from main
. I don't call fgets
directly from main
.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
//forward declarations
void get_line_from_user( const char prompt[], char buffer[], int buffer_size );
int get_int_from_user( const char *prompt );
#define NUM_STUDENTS 2
#define MAX_STRING_SIZE 200
int main( void )
{
typedef struct
{
char* firstName;
char* lastName;
int rollNumber;
} STUDENT;
STUDENT* students = malloc( NUM_STUDENTS * sizeof *students );
//fill student data from user
for ( int i = 0; i < NUM_STUDENTS; i++)
{
students[i].firstName = malloc( MAX_STRING_SIZE );
get_line_from_user(
"Enter first name: ",
students[i].firstName,
MAX_STRING_SIZE
);
//shrink the allocated memory buffers to the
//required size
students[i].firstName = realloc(
students[i].firstName,
strlen( students[i].firstName ) + 1
);
students[i].lastName = malloc( MAX_STRING_SIZE );
get_line_from_user(
"Enter last name: ",
students[i].lastName,
MAX_STRING_SIZE
);
students[i].rollNumber =
get_int_from_user( "Enter roll number: " );
//shrink the allocated memory buffers to the
//required size
students[i].lastName = realloc(
students[i].lastName,
strlen( students[i].lastName ) + 1
);
}
//print back the stored input
for ( int i = 0; i < NUM_STUDENTS; i++)
printf(
"First Name: %s, Last Name: %s, Roll number: %d\n",
students[i].firstName, students[i].lastName,
students[i].rollNumber
);
return EXIT_SUCCESS;
}
//This function will read exactly one line of input from the
//user. It will remove the newline character, if it exists. If
//the line is too long to fit in the buffer, then the function
//will automatically reprompt the user for input. On failure,
//the function will never return, but will print an error
//message and call "exit" instead.
void get_line_from_user( const char prompt[], char buffer[], int buffer_size )
{
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
fputs( prompt, stdout );
//attempt to read one line of input
if ( fgets( buffer, buffer_size, stdin ) == NULL )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
//attempt to find newline character
p = strchr( buffer, '\n' );
//make sure that entire line was read in (i.e. that
//the buffer was not too small to store the entire line)
if ( p == NULL )
{
int c;
//a missing newline character is ok if the next
//character is a newline character or if we have
//reached end-of-file (for example if the input is
//being piped from a file or if the user enters
//end-of-file in the terminal itself)
if ( (c=getchar()) != '\n' && !feof(stdin) )
{
if ( ferror(stdin) )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
printf( "Input was too long to fit in buffer!\n" );
//discard remainder of line
do
{
c = getchar();
if ( ferror(stdin) )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' && c != EOF );
//reprompt user for input by restarting loop
continue;
}
}
else
{
//remove newline character by overwriting it with
//null character
*p = '#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
//forward declarations
void get_line_from_user( const char prompt[], char buffer[], int buffer_size );
int get_int_from_user( const char *prompt );
#define NUM_STUDENTS 2
#define MAX_STRING_SIZE 200
int main( void )
{
typedef struct
{
char* firstName;
char* lastName;
int rollNumber;
} STUDENT;
STUDENT* students = malloc( NUM_STUDENTS * sizeof *students );
//fill student data from user
for ( int i = 0; i < NUM_STUDENTS; i++)
{
students[i].firstName = malloc( MAX_STRING_SIZE );
get_line_from_user(
"Enter first name: ",
students[i].firstName,
MAX_STRING_SIZE
);
//shrink the allocated memory buffers to the
//required size
students[i].firstName = realloc(
students[i].firstName,
strlen( students[i].firstName ) + 1
);
students[i].lastName = malloc( MAX_STRING_SIZE );
get_line_from_user(
"Enter last name: ",
students[i].lastName,
MAX_STRING_SIZE
);
students[i].rollNumber =
get_int_from_user( "Enter roll number: " );
//shrink the allocated memory buffers to the
//required size
students[i].lastName = realloc(
students[i].lastName,
strlen( students[i].lastName ) + 1
);
}
//print back the stored input
for ( int i = 0; i < NUM_STUDENTS; i++)
printf(
"First Name: %s, Last Name: %s, Roll number: %d\n",
students[i].firstName, students[i].lastName,
students[i].rollNumber
);
return EXIT_SUCCESS;
}
//This function will read exactly one line of input from the
//user. It will remove the newline character, if it exists. If
//the line is too long to fit in the buffer, then the function
//will automatically reprompt the user for input. On failure,
//the function will never return, but will print an error
//message and call "exit" instead.
void get_line_from_user( const char prompt[], char buffer[], int buffer_size )
{
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
fputs( prompt, stdout );
//attempt to read one line of input
if ( fgets( buffer, buffer_size, stdin ) == NULL )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
//attempt to find newline character
p = strchr( buffer, '\n' );
//make sure that entire line was read in (i.e. that
//the buffer was not too small to store the entire line)
if ( p == NULL )
{
int c;
//a missing newline character is ok if the next
//character is a newline character or if we have
//reached end-of-file (for example if the input is
//being piped from a file or if the user enters
//end-of-file in the terminal itself)
if ( (c=getchar()) != '\n' && !feof(stdin) )
{
if ( ferror(stdin) )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
printf( "Input was too long to fit in buffer!\n" );
//discard remainder of line
do
{
c = getchar();
if ( ferror(stdin) )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' && c != EOF );
//reprompt user for input by restarting loop
continue;
}
}
else
{
//remove newline character by overwriting it with
//null character
*p = '\0';
}
//input was ok, so break out of loop
break;
}
}
//This function will attempt to read one integer from the user. If
//the input is invalid, it will automatically reprompt the user,
//until the input is valid.
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6abc" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
';
}
//input was ok, so break out of loop
break;
}
}
//This function will attempt to read one integer from the user. If
//the input is invalid, it will automatically reprompt the user,
//until the input is valid.
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6abc" gets rejected
for ( ; *p != '#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
//forward declarations
void get_line_from_user( const char prompt[], char buffer[], int buffer_size );
int get_int_from_user( const char *prompt );
#define NUM_STUDENTS 2
#define MAX_STRING_SIZE 200
int main( void )
{
typedef struct
{
char* firstName;
char* lastName;
int rollNumber;
} STUDENT;
STUDENT* students = malloc( NUM_STUDENTS * sizeof *students );
//fill student data from user
for ( int i = 0; i < NUM_STUDENTS; i++)
{
students[i].firstName = malloc( MAX_STRING_SIZE );
get_line_from_user(
"Enter first name: ",
students[i].firstName,
MAX_STRING_SIZE
);
//shrink the allocated memory buffers to the
//required size
students[i].firstName = realloc(
students[i].firstName,
strlen( students[i].firstName ) + 1
);
students[i].lastName = malloc( MAX_STRING_SIZE );
get_line_from_user(
"Enter last name: ",
students[i].lastName,
MAX_STRING_SIZE
);
students[i].rollNumber =
get_int_from_user( "Enter roll number: " );
//shrink the allocated memory buffers to the
//required size
students[i].lastName = realloc(
students[i].lastName,
strlen( students[i].lastName ) + 1
);
}
//print back the stored input
for ( int i = 0; i < NUM_STUDENTS; i++)
printf(
"First Name: %s, Last Name: %s, Roll number: %d\n",
students[i].firstName, students[i].lastName,
students[i].rollNumber
);
return EXIT_SUCCESS;
}
//This function will read exactly one line of input from the
//user. It will remove the newline character, if it exists. If
//the line is too long to fit in the buffer, then the function
//will automatically reprompt the user for input. On failure,
//the function will never return, but will print an error
//message and call "exit" instead.
void get_line_from_user( const char prompt[], char buffer[], int buffer_size )
{
for (;;) //infinite loop, equivalent to while(1)
{
char *p;
//prompt user for input
fputs( prompt, stdout );
//attempt to read one line of input
if ( fgets( buffer, buffer_size, stdin ) == NULL )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
//attempt to find newline character
p = strchr( buffer, '\n' );
//make sure that entire line was read in (i.e. that
//the buffer was not too small to store the entire line)
if ( p == NULL )
{
int c;
//a missing newline character is ok if the next
//character is a newline character or if we have
//reached end-of-file (for example if the input is
//being piped from a file or if the user enters
//end-of-file in the terminal itself)
if ( (c=getchar()) != '\n' && !feof(stdin) )
{
if ( ferror(stdin) )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
printf( "Input was too long to fit in buffer!\n" );
//discard remainder of line
do
{
c = getchar();
if ( ferror(stdin) )
{
printf( "Error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' && c != EOF );
//reprompt user for input by restarting loop
continue;
}
}
else
{
//remove newline character by overwriting it with
//null character
*p = '\0';
}
//input was ok, so break out of loop
break;
}
}
//This function will attempt to read one integer from the user. If
//the input is invalid, it will automatically reprompt the user,
//until the input is valid.
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//prompt user for input
fputs( prompt, stdout );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6abc" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
This program has the following behavior:
Enter first name: This line is longer than 200 characters. This line is longer than 200 characters. This line is longer than 200 characters. This line is longer than 200 characters. This line is longer than 200 characters.
Input was too long to fit in buffer!
Enter first name: John
Enter last name: Doe
Enter roll number: 8
Enter first name: Jane
Enter last name: Doe
Enter roll number: 9
First Name: John, Last Name: Doe, Roll number: 8
First Name: Jane, Last Name: Doe, Roll number: 9
Note that it is generally recommended to always check the return value of malloc
, because otherwise, if malloc
fails for some reason, then the program will misbehave. I did not add these checks to my code, because I did not want to distract from the other changes I made.
答案2
得分: 3
// https://www.indiatimes.com/news/weird/five-incredibly-long-names-in-the-world-and-the-not-soordinary-people-who-have-them-243597.html
#define NAME_SIZE_MAX (1000 + 1 /* '// https://www.indiatimes.com/news/weird/five-incredibly-long-names-in-the-world-and-the-not-soordinary-people-who-have-them-243597.html
#define NAME_SIZE_MAX (1000 + 1 /* '\0' */)
char *read_name_alloc(const char * prompt) {
if (prompt) fputs(prompt, stdout);
char buf[NAME_SIZE_MAX + 1]; // 1 more for '\n'.
if (fgets(buf, sizeof buf, stdin) == NULL) {
return NULL;
}
// Lop off terminating null character.
buf[strcspn(buf, "\n\r")] = '\0';
return strdup(buf);
}
...
for (x = 0; x < numStudents; x++) {
// Error checking omitted for brevity.
students[x].firstName = read_name_alloc("Enter first name :");
students[x].lastName = read_name_alloc("Enter last name :");
students[x].rollNumber = read_int("Enter roll number :", 0 /* man */, INT_MAX /* max */);
}
for (x = 0; x < numStudents; x++) {
printf("First Name: %s, Last Name: %s, Roll number: %d\n",
students[x].firstName,students[x].lastName,students[x].rollNumber);
}
' */)
char *read_name_alloc(const char * prompt) {
if (prompt) fputs(prompt, stdout);
char buf[NAME_SIZE_MAX + 1]; // 1 more for '\n'.
if (fgets(buf, sizeof buf, stdin) == NULL) {
return NULL;
}
// Lop off terminating null character.
buf[strcspn(buf, "\n\r")] = '// https://www.indiatimes.com/news/weird/five-incredibly-long-names-in-the-world-and-the-not-soordinary-people-who-have-them-243597.html
#define NAME_SIZE_MAX (1000 + 1 /* '\0' */)
char *read_name_alloc(const char * prompt) {
if (prompt) fputs(prompt, stdout);
char buf[NAME_SIZE_MAX + 1]; // 1 more for '\n'.
if (fgets(buf, sizeof buf, stdin) == NULL) {
return NULL;
}
// Lop off terminating null character.
buf[strcspn(buf, "\n\r")] = '\0';
return strdup(buf);
}
...
for (x = 0; x < numStudents; x++) {
// Error checking omitted for brevity.
students[x].firstName = read_name_alloc("Enter first name :");
students[x].lastName = read_name_alloc("Enter last name :");
students[x].rollNumber = read_int("Enter roll number :", 0 /* man */, INT_MAX /* max */);
}
for (x = 0; x < numStudents; x++) {
printf("First Name: %s, Last Name: %s, Roll number: %d\n",
students[x].firstName,students[x].lastName,students[x].rollNumber);
}
';
return strdup(buf);
}
...
for (x = 0; x < numStudents; x++) {
// Error checking omitted for brevity.
students[x].firstName = read_name_alloc("Enter first name :");
students[x].lastName = read_name_alloc("Enter last name :");
students[x].rollNumber = read_int("Enter roll number :", 0 /* man */, INT_MAX /* max */);
}
for (x = 0; x < numStudents; x++) {
printf("First Name: %s, Last Name: %s, Roll number: %d\n",
students[x].firstName,students[x].lastName,students[x].rollNumber);
}
英文:
@Andreas Wenzel well answers what is wrong with OP's code.
Yet better to avoid "%s"
as that does not handle spaces in first or last names.
Consider dropping all use of scanf()
and move to fgets()
.
Suggested alternative code that uses a helper function to read a name. There are some weaknesses in the helper function, but that can easily be improved, depending on coding goals. Also suggest a likewise helper function to read the number of students.
// https://www.indiatimes.com/news/weird/five-incredibly-long-names-in-the-world-and-the-not-soordinary-people-who-have-them-243597.html
#define NAME_SIZE_MAX (1000 + 1 /* '// https://www.indiatimes.com/news/weird/five-incredibly-long-names-in-the-world-and-the-not-soordinary-people-who-have-them-243597.html
#define NAME_SIZE_MAX (1000 + 1 /* '\0' */)
char *read_name_alloc(const char * prompt) {
if (prompt) fputs(prompt, stdout);
char buf[NAME_SIZE_MAX + 1]; // 1 more for `\n`.
if (fgets(buf, sizeof buf, stdin) == NULL) {
return NULL;
}
// Lop off terminating null character.
buf[strcspn(buf, "\n\r")] = '\0';
return strdup(buf);
}
...
for (x = 0; x < numStudents; x++) {
// Error checking omitted for brevity.
students[x].firstName = read_name_alloc("Enter first name :");
students[x].lastName = read_name_alloc("Enter last name :");
students[x].rollNumber = read_int("Enter roll number :", 0 /* man */, INT_MAX /* max */);
}
for (x = 0; x < numStudents; x++) {
printf("First Name: %s, Last Name: %s, Roll number: %d\n",
students[x].firstName,students[x].lastName,students[x].rollNumber);
}
' */)
char *read_name_alloc(const char * prompt) {
if (prompt) fputs(prompt, stdout);
char buf[NAME_SIZE_MAX + 1]; // 1 more for `\n`.
if (fgets(buf, sizeof buf, stdin) == NULL) {
return NULL;
}
// Lop off terminating null character.
buf[strcspn(buf, "\n\r")] = '// https://www.indiatimes.com/news/weird/five-incredibly-long-names-in-the-world-and-the-not-soordinary-people-who-have-them-243597.html
#define NAME_SIZE_MAX (1000 + 1 /* '\0' */)
char *read_name_alloc(const char * prompt) {
if (prompt) fputs(prompt, stdout);
char buf[NAME_SIZE_MAX + 1]; // 1 more for `\n`.
if (fgets(buf, sizeof buf, stdin) == NULL) {
return NULL;
}
// Lop off terminating null character.
buf[strcspn(buf, "\n\r")] = '\0';
return strdup(buf);
}
...
for (x = 0; x < numStudents; x++) {
// Error checking omitted for brevity.
students[x].firstName = read_name_alloc("Enter first name :");
students[x].lastName = read_name_alloc("Enter last name :");
students[x].rollNumber = read_int("Enter roll number :", 0 /* man */, INT_MAX /* max */);
}
for (x = 0; x < numStudents; x++) {
printf("First Name: %s, Last Name: %s, Roll number: %d\n",
students[x].firstName,students[x].lastName,students[x].rollNumber);
}
';
return strdup(buf);
}
...
for (x = 0; x < numStudents; x++) {
// Error checking omitted for brevity.
students[x].firstName = read_name_alloc("Enter first name :");
students[x].lastName = read_name_alloc("Enter last name :");
students[x].rollNumber = read_int("Enter roll number :", 0 /* man */, INT_MAX /* max */);
}
for (x = 0; x < numStudents; x++) {
printf("First Name: %s, Last Name: %s, Roll number: %d\n",
students[x].firstName,students[x].lastName,students[x].rollNumber);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论