关于 malloc 的询问(char*)

huangapple go评论65阅读模式
英文:

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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

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 &lt; numStudents; x++)
    {
        students[x].firstName=(char*)malloc(sizeof(char*));
       
        printf(&quot;Enter first name :&quot;);
        scanf(&quot;%s&quot;,students[x].firstName);
        students[x].lastName=(char*)malloc(sizeof(char*));
        printf(&quot;Enter last name :&quot;);
        scanf(&quot;%s&quot;,students[x].lastName);
        printf(&quot;Enter roll number  :&quot;);
        scanf(&quot;%d&quot;,&amp;students[x].rollNumber);
    }

    for (x = 0; x &lt; numStudents; x++)
        printf(&quot;First Name: %s, Last Name: %s, Roll number: %d\n&quot;, 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_userget_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(&quot;Enter first name :&quot;);
scanf(&quot;%s&quot;,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( &quot;%199s&quot;, students[x].firstName );

instead of:

scanf(&quot;%s&quot;,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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;ctype.h&gt;
#include &lt;limits.h&gt;
#include &lt;errno.h&gt;

//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 &lt; NUM_STUDENTS; i++)
    {
        students[i].firstName = malloc( MAX_STRING_SIZE );

        get_line_from_user(
            &quot;Enter first name: &quot;,
            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(
            &quot;Enter last name: &quot;,
            students[i].lastName,
            MAX_STRING_SIZE
        );

        students[i].rollNumber =
            get_int_from_user( &quot;Enter roll number: &quot; );

        //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 &lt; NUM_STUDENTS; i++)
        printf(
            &quot;First Name: %s, Last Name: %s, Roll number: %d\n&quot;,
            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 &quot;exit&quot; 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( &quot;Error reading from input!\n&quot; );
            exit( EXIT_FAILURE );
        }

        //attempt to find newline character
        p = strchr( buffer, &#39;\n&#39; );

        //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()) != &#39;\n&#39; &amp;&amp; !feof(stdin) )
            {
                if ( ferror(stdin) )
                {
                    printf( &quot;Error reading from input!\n&quot; );
                    exit( EXIT_FAILURE );
                }

                printf( &quot;Input was too long to fit in buffer!\n&quot; );

                //discard remainder of line
                do
                {
                    c = getchar();

                    if ( ferror(stdin) )
                    {
                        printf( &quot;Error reading from input!\n&quot; );
                        exit( EXIT_FAILURE );
                    }

                } while ( c != &#39;\n&#39; &amp;&amp; c != EOF );

                //reprompt user for input by restarting loop
                continue;
            }
        }
        else
        {
            //remove newline character by overwriting it with
            //null character
            *p = &#39;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;ctype.h&gt;
#include &lt;limits.h&gt;
#include &lt;errno.h&gt;
//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 &lt; NUM_STUDENTS; i++)
{
students[i].firstName = malloc( MAX_STRING_SIZE );
get_line_from_user(
&quot;Enter first name: &quot;,
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(
&quot;Enter last name: &quot;,
students[i].lastName,
MAX_STRING_SIZE
);
students[i].rollNumber =
get_int_from_user( &quot;Enter roll number: &quot; );
//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 &lt; NUM_STUDENTS; i++)
printf(
&quot;First Name: %s, Last Name: %s, Roll number: %d\n&quot;,
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 &quot;exit&quot; 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( &quot;Error reading from input!\n&quot; );
exit( EXIT_FAILURE );
}
//attempt to find newline character
p = strchr( buffer, &#39;\n&#39; );
//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()) != &#39;\n&#39; &amp;&amp; !feof(stdin) )
{
if ( ferror(stdin) )
{
printf( &quot;Error reading from input!\n&quot; );
exit( EXIT_FAILURE );
}
printf( &quot;Input was too long to fit in buffer!\n&quot; );
//discard remainder of line
do
{
c = getchar();
if ( ferror(stdin) )
{
printf( &quot;Error reading from input!\n&quot; );
exit( EXIT_FAILURE );
}
} while ( c != &#39;\n&#39; &amp;&amp; c != EOF );
//reprompt user for input by restarting loop
continue;
}
}
else
{
//remove newline character by overwriting it with
//null character
*p = &#39;\0&#39;;
}
//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, &quot;Unrecoverable input error!\n&quot; );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, &#39;\n&#39; ) == NULL &amp;&amp; !feof( stdin ) )
{
int c;
printf( &quot;Line input was too long!\n&quot; );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, &quot;Unrecoverable error reading from input!\n&quot; );
exit( EXIT_FAILURE );
}
} while ( c != &#39;\n&#39; );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &amp;p, 10 );
if ( p == buffer )
{
printf( &quot;Error converting string to number!\n&quot; );
continue;
}
//make sure that number is representable as an &quot;int&quot;
if ( errno == ERANGE || l &lt; INT_MIN || l &gt; INT_MAX )
{
printf( &quot;Number out of range error!\n&quot; );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as &quot;6abc&quot; gets rejected
for ( ; *p != &#39;\0&#39;; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( &quot;Unexpected input encountered!\n&quot; );
//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;
}
}
&#39;; } //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, &quot;Unrecoverable input error!\n&quot; ); exit( EXIT_FAILURE ); } //make sure that entire line was read in (i.e. that //the buffer was not too small) if ( strchr( buffer, &#39;\n&#39; ) == NULL &amp;&amp; !feof( stdin ) ) { int c; printf( &quot;Line input was too long!\n&quot; ); //discard remainder of line do { c = getchar(); if ( c == EOF ) { fprintf( stderr, &quot;Unrecoverable error reading from input!\n&quot; ); exit( EXIT_FAILURE ); } } while ( c != &#39;\n&#39; ); continue; } //attempt to convert string to number errno = 0; l = strtol( buffer, &amp;p, 10 ); if ( p == buffer ) { printf( &quot;Error converting string to number!\n&quot; ); continue; } //make sure that number is representable as an &quot;int&quot; if ( errno == ERANGE || l &lt; INT_MIN || l &gt; INT_MAX ) { printf( &quot;Number out of range error!\n&quot; ); continue; } //make sure that remainder of line contains only whitespace, //so that input such as &quot;6abc&quot; gets rejected for ( ; *p != &#39;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;ctype.h&gt;
#include &lt;limits.h&gt;
#include &lt;errno.h&gt;
//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 &lt; NUM_STUDENTS; i++)
{
students[i].firstName = malloc( MAX_STRING_SIZE );
get_line_from_user(
&quot;Enter first name: &quot;,
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(
&quot;Enter last name: &quot;,
students[i].lastName,
MAX_STRING_SIZE
);
students[i].rollNumber =
get_int_from_user( &quot;Enter roll number: &quot; );
//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 &lt; NUM_STUDENTS; i++)
printf(
&quot;First Name: %s, Last Name: %s, Roll number: %d\n&quot;,
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 &quot;exit&quot; 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( &quot;Error reading from input!\n&quot; );
exit( EXIT_FAILURE );
}
//attempt to find newline character
p = strchr( buffer, &#39;\n&#39; );
//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()) != &#39;\n&#39; &amp;&amp; !feof(stdin) )
{
if ( ferror(stdin) )
{
printf( &quot;Error reading from input!\n&quot; );
exit( EXIT_FAILURE );
}
printf( &quot;Input was too long to fit in buffer!\n&quot; );
//discard remainder of line
do
{
c = getchar();
if ( ferror(stdin) )
{
printf( &quot;Error reading from input!\n&quot; );
exit( EXIT_FAILURE );
}
} while ( c != &#39;\n&#39; &amp;&amp; c != EOF );
//reprompt user for input by restarting loop
continue;
}
}
else
{
//remove newline character by overwriting it with
//null character
*p = &#39;\0&#39;;
}
//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, &quot;Unrecoverable input error!\n&quot; );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, &#39;\n&#39; ) == NULL &amp;&amp; !feof( stdin ) )
{
int c;
printf( &quot;Line input was too long!\n&quot; );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, &quot;Unrecoverable error reading from input!\n&quot; );
exit( EXIT_FAILURE );
}
} while ( c != &#39;\n&#39; );
continue;
}
//attempt to convert string to number
errno = 0;
l = strtol( buffer, &amp;p, 10 );
if ( p == buffer )
{
printf( &quot;Error converting string to number!\n&quot; );
continue;
}
//make sure that number is representable as an &quot;int&quot;
if ( errno == ERANGE || l &lt; INT_MIN || l &gt; INT_MAX )
{
printf( &quot;Number out of range error!\n&quot; );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as &quot;6abc&quot; gets rejected
for ( ; *p != &#39;\0&#39;; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( &quot;Unexpected input encountered!\n&quot; );
//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;
}
}
&#39;; p++ ) { if ( !isspace( (unsigned char)*p ) ) { printf( &quot;Unexpected input encountered!\n&quot; ); //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 &quot;%s&quot; 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 /* &#39;
// 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 /* &#39;\0&#39; */)
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, &quot;\n\r&quot;)] = &#39;\0&#39;;
return strdup(buf);
}
...
for (x = 0; x &lt; numStudents; x++) {
// Error checking omitted for brevity. 
students[x].firstName = read_name_alloc(&quot;Enter first name :&quot;);
students[x].lastName = read_name_alloc(&quot;Enter last name :&quot;);
students[x].rollNumber = read_int(&quot;Enter roll number  :&quot;, 0 /* man */, INT_MAX /* max */);
}
for (x = 0; x &lt; numStudents; x++) {
printf(&quot;First Name: %s, Last Name: %s, Roll number: %d\n&quot;,
students[x].firstName,students[x].lastName,students[x].rollNumber);
}
&#39; */) 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, &quot;\n\r&quot;)] = &#39;
// 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 /* &#39;\0&#39; */)
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, &quot;\n\r&quot;)] = &#39;\0&#39;;
return strdup(buf);
}
...
for (x = 0; x &lt; numStudents; x++) {
// Error checking omitted for brevity. 
students[x].firstName = read_name_alloc(&quot;Enter first name :&quot;);
students[x].lastName = read_name_alloc(&quot;Enter last name :&quot;);
students[x].rollNumber = read_int(&quot;Enter roll number  :&quot;, 0 /* man */, INT_MAX /* max */);
}
for (x = 0; x &lt; numStudents; x++) {
printf(&quot;First Name: %s, Last Name: %s, Roll number: %d\n&quot;,
students[x].firstName,students[x].lastName,students[x].rollNumber);
}
&#39;; return strdup(buf); } ... for (x = 0; x &lt; numStudents; x++) { // Error checking omitted for brevity. students[x].firstName = read_name_alloc(&quot;Enter first name :&quot;); students[x].lastName = read_name_alloc(&quot;Enter last name :&quot;); students[x].rollNumber = read_int(&quot;Enter roll number :&quot;, 0 /* man */, INT_MAX /* max */); } for (x = 0; x &lt; numStudents; x++) { printf(&quot;First Name: %s, Last Name: %s, Roll number: %d\n&quot;, students[x].firstName,students[x].lastName,students[x].rollNumber); }

huangapple
  • 本文由 发表于 2023年6月5日 10:08:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76403154.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定