当我将 Scanf 放入它自己的函数中时它不起作用?

When i put Scanf in it own function it doesn't work?

我编写了这段用于乘法矩阵的代码。它可以工作,但是当我尝试将它放入它自己的函数中时,它会停止工作。为什么要这样做?

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

/* Ask for elements to insert inside matrixes.*/
void AddValues(int row, int col, float **ptr, int matrixNumber) {
    printf("\nWrite elements to insert into %d. matrix :\n", matrixNumber);
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            printf("\tA[%d][%d] = ", i, j);
            scanf("%f", &ptr[i][j]);
        }
    }
}

void Multiply(int row1, int col1, int col2, float **ptr1, float **ptr2, float **ptr3) {
    /* Multiplication. */
    for (int i = 0; i < row1; i++)  {
        for (int j = 0; j < col1; j++) {
            ptr3[i][j] = 0;
            for (int k = 0; k < col2; k++)
                ptr3[i][j] = ptr3[i][j] + ptr1[i][k] * ptr2[k][j];
        }
    }
}

void WriteOut(int row1, int col2, float **ptr3) {
    /* Print final matrix. */
    printf("\n\nFinal Matrix :");
    for (int i = 0; i < row1; i++) {
        printf("\n\t\t\t");
        for (int j = 0; j < col2; j++)
            printf("%f\t", ptr3[i][j]);
    }
}

void HighestSum(int row1, int col2, float **ptr3) {
    printf("\n\nrow with highest sum of elements :");
    float max = 0;
    float sum;
    for (int i = 0; i < row1; ++i) {
        for (int j = 0; j < col2; ++j){
            sum = sum + ptr3[i][j];
            if (j == col2 - 1)
                printf("\n");
        }
        if (max == 0)
            max = sum;
        if (max < sum)
            max = sum;
        sum = 0;
    }
    printf("Highest sum of elements in row: %f  ", max);
}

int main() {
    float **ptr1, **ptr2, **ptr3;
    int row1, col1, row2, col2;
    int i;
    printf("\nWrite numbers of rows for first matrix. : ");
    scanf("%d", &row1);
    printf("\nWrite numbers of columns for first matrix. : ");
    scanf("%d", &col1);
    printf("\nWrite numbers of rows for second matrix. : ");
    scanf("%d", &row2);
    printf("\nWrite numbers of columns for second matrix. : ");
    scanf("%d", &col2);
    if (col1 != row2) {
        printf("\nMatrixes can't be multiplied.");
        return (0);
    }
    if (col1 <= 0 || row1 <= 0 || col2 <= 0 || row2 <= 0) {
        printf("\nNumbers have to be positive.");
        return (0);
    }
    /* Allocation. */
    ptr1 = (float **)malloc(sizeof(float *) * row1);
    ptr2 = (float **)malloc(sizeof(float *) * row2);
    ptr3 = (float **)malloc(sizeof(float *) * row1);
    for (i = 0; i < row1; i++)
        ptr1[i] = (float *)malloc(sizeof(float) * col1);
    for (i = 0; i < row2; i++)
        ptr2[i] = (float *)malloc(sizeof(float) * col2);
    for (i = 0; i < row1; i++)
        ptr3[i] = (float *)malloc(sizeof(float) * col2);
    AddValues(row1, col1, ptr1, 1);
    AddValues(row2, col2, ptr2, 2);
    Multiply(row1, col1, col2, ptr1, ptr2, ptr3);
    WriteOut(row1, col2, ptr3);
    HighestSum(row1, col2, ptr3);
    return 0;
}

这样写的程序可以运行。然而,当我把 scanf 放在它自己的函数中时,它不会

void Scanner(int row1, int col1, int row2, int col2) {
    printf("\nWrite numbers of rows for first matrix. : ");
    scanf("%d", &row1);
    printf("\nWrite numbers of columns for first matrix. : ");
    scanf("%d", &col1);
    printf("\nWrite numbers of rows for second matrix. : ");
    scanf("%d", &row2);
    printf("\nWrite numbers of columns for second matrix. : ");
    scanf("%d", &col2);
    if (col1 != row2) {
        printf("\nMatrixes can't be multiplied.");
        return (0);
    }
    if (col1 <= 0 || row1 <= 0 || col2 <= 0 || row2 <= 0) {
        printf("\nNumbers have to be positive.");
        return (0);
    }
}

该程序将询问行和列的大小,但随后停止。我怎样才能让它发挥作用?

在函数Scanner中,参数是按值传递的。这意味着函数 Scanner 将获得这些变量自己的副本,并且更改这些副本的值不会更改函数 main.

中原始变量的值

如果你想让函数Scanner能够改变函数main中的原始变量的值,那么你不应该传递原始变量的值,但是你应该而是传递指向函数 main 中原始变量的指针。这样,函数 Scanner 可以使用指针直接写入原始变量。

我建议您将函数 Scanner 更改为以下内容:

void Scanner( int *p_row1, int *p_col1, int *p_row2, int *p_col2 )
{
    printf( "Write numbers of rows for first matrix: " );
    scanf( "%d", p_row1 );
    printf( "Write numbers of columns for first matrix: " );
    scanf( "%d", p_col1 );
    printf( "Write numbers of rows for second matrix: " );
    scanf( "%d", p_row2 );
    printf( "Write numbers of columns for second matrix: " );
    scanf( "%d", p_col2 );

    if( *p_col1 != *p_row2 )
    {
        printf( "Matrixes can't be multiplied.\n" );
        exit( EXIT_FAILURE );
    }

    if( *p_col1 <= 0 || *p_row1 <= 0 || *p_col2 <= 0 || *p_row2 <= 0 )
    {
        printf( "Numbers have to be positive.\n" );
        exit( EXIT_FAILURE );
    }
}

我在变量名中添加的前缀p_只是代表“指针”,但您不必使用该前缀。你可以给他们任何你想要的名字。

您可以像这样从函数 main 调用函数 Scanner

Scanner( &row1, &col1, &row2, &col2 );

此外,由于您正在处理用户输入,因此最好始终检查 scanf 的 return 值,以确定函数是否成功。否则,如果用户输入的不是数字,转换将失败,但您的程序仍将尝试处理 non-existant 转换后的值。

因此,这样写函数可能会更好:

void Scanner( int *p_row1, int *p_col1, int *p_row2, int *p_col2 )
{
    printf( "Write numbers of rows for first matrix: " );
    if ( scanf( "%d", p_row1 ) != 1 )
    {
        printf( "Input error!\n" );
        exit( EXIT_FAILURE );
    }

    printf( "Write numbers of columns for first matrix: " );
    if ( scanf( "%d", p_col1 ) != 1 )
    {
        printf( "Input error!\n" );
        exit( EXIT_FAILURE );
    }

    printf( "Write numbers of rows for second matrix: " );
    if ( scanf( "%d", p_row2 ) != 1 )
    {
        printf( "Input error!\n" );
        exit( EXIT_FAILURE );
    }

    printf( "Write numbers of columns for second matrix: " );
    if ( scanf( "%d", p_col2 ) != 1 )
    {
        printf( "Input error!\n" );
        exit( EXIT_FAILURE );
    }

    if( *p_col1 != *p_row2 )
    {
        printf( "Matrixes can't be multiplied.\n" );
        exit( EXIT_FAILURE );
    }

    if( *p_col1 <= 0 || *p_row1 <= 0 || *p_col2 <= 0 || *p_row2 <= 0 )
    {
        printf( "Numbers have to be positive.\n" );
        exit( EXIT_FAILURE );
    }
}

但是,这个解决方案仍然没有很好地执行输入验证。例如,如果用户输入数字 6abc,那么 scanf 将接受此输入作为数字 6 的有效输入。如果您不想这样做,那么您可能需要使用 中的函数 get_int_from_user。该函数将执行非常严格的输入验证,如果输入不是数字,它将自动重新提示用户输入。

如果您决定使用我的函数 get_int_from_user,那么您可以这样编写函数:

void Scanner( int *p_row1, int *p_col1, int *p_row2, int *p_col2 )
{
    *p_row1 = get_int_from_user(
        "Write numbers of rows for first matrix: "
    );

    *p_col1 = get_int_from_user(
        "Write numbers of columns for first matrix: "
    );

    *p_row2 = get_int_from_user(
        "Write numbers of rows for second matrix: "
    );

    *p_col2 = get_int_from_user(
        "Write numbers of columns for second matrix: "
    );

    if( *p_col1 != *p_row2 )
    {
        printf( "Matrixes can't be multiplied.\n" );
        exit( EXIT_FAILURE );
    }

    if( *p_col1 <= 0 || *p_row1 <= 0 || *p_col2 <= 0 || *p_row2 <= 0 )
    {
        printf( "Numbers have to be positive.\n" );
        exit( EXIT_FAILURE );
    }
}

不过,现在当输入的不是数字时,函数 get_int_from_user 会自动重新提示用户,但当输入因其他原因无效时,根本不会重新提示用户。为了解决这个不一致,函数可以这样写:

void Scanner( int *p_row1, int *p_col1, int *p_row2, int *p_col2 )
{
    //loop forever until input is valid
    for (;;) //infinite loop, equivalent to while(1)
    {
        *p_row1 = get_int_from_user(
            "Write numbers of rows for first matrix: "
        );

        *p_col1 = get_int_from_user(
            "Write numbers of columns for first matrix: "
        );

        *p_row2 = get_int_from_user(
            "Write numbers of rows for second matrix: "
        );

        *p_col2 = get_int_from_user(
            "Write numbers of columns for second matrix: "
        );

        if( *p_col1 != *p_row2 )
        {
            printf( "Matrixes can't be multiplied. Try again!\n\n" );
            continue;
        }

        if( *p_col1 <= 0 || *p_row1 <= 0 || *p_col2 <= 0 || *p_row2 <= 0 )
        {
            printf( "Numbers have to be positive.\n\n" );
            continue;
        }

        //input is valid, so we can break out of the infinite loop
        break;
    }
}

可以通过在用户输入一个 non-positive 号码后立即重新启动输入来进一步改进此程序,而不是等到用户输入所有 4 个号码。不过,我不想让我的回答太复杂。

这里是最新版本功能的一个小演示程序Scanner:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>

void Scanner( int *p_row1, int *p_col1, int *p_row2, int *p_col2 );
int get_int_from_user( const char *prompt );

int main( void )
{
    int row1, col1, row2, col2;

    Scanner( &row1, &col1, &row2, &col2 );

    printf(
        "\n"
        "The variables in the function main now have the\n"
        "following values:\n"
        "\n"
        "row1: %d\n"
        "col1: %d\n"
        "row2: %d\n"
        "col2: %d\n",
        row1, col1, row2, col2
    );
}

void Scanner( int *p_row1, int *p_col1, int *p_row2, int *p_col2 )
{
    //loop forever until input is valid
    for (;;) //infinite loop, equivalent to while(1)
    {
        *p_row1 = get_int_from_user(
            "Write numbers of rows for first matrix: "
        );

        *p_col1 = get_int_from_user(
            "Write numbers of columns for first matrix: "
        );

        *p_row2 = get_int_from_user(
            "Write numbers of rows for second matrix: "
        );

        *p_col2 = get_int_from_user(
            "Write numbers of columns for second matrix: "
        );

        if( *p_col1 != *p_row2 )
        {
            printf( "Matrixes can't be multiplied. Try again!\n\n" );
            continue;
        }

        if( *p_col1 <= 0 || *p_row1 <= 0 || *p_col2 <= 0 || *p_row2 <= 0 )
        {
            printf( "Numbers have to be positive.\n\n" );
            continue;
        }

        //input is valid, so we can break out of the infinite loop
        break;
    }
}

int get_int_from_user( const char *prompt )
{
    for (;;) //loop forever until user enters a valid number
    {
        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 error reading from input!\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 "6sdfj23jlj" gets rejected
        for ( ; *p != '[=15=]'; 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;
    }
}

此程序具有以下行为

Write numbers of rows for first matrix: abc
error converting string to number!
Write numbers of rows for first matrix: 6abc
unexpected input encountered!
Write numbers of rows for first matrix: 6
Write numbers of columns for first matrix: 7
Write numbers of rows for second matrix: 8
Write numbers of columns for second matrix: 9
Matrixes can't be multiplied. Try again!

Write numbers of rows for first matrix: 6
Write numbers of columns for first matrix: 7
Write numbers of rows for second matrix: 7
Write numbers of columns for second matrix: 8

The variables in the function main now have the
following values:

row1: 6
col1: 7
row2: 7
col2: 8