允许用户在数组函数中更改“5”的值

Posted

技术标签:

【中文标题】允许用户在数组函数中更改“5”的值【英文标题】:Allows the user to change the value of "5" inside array function 【发布时间】:2022-01-03 23:36:13 【问题描述】:

正如我的标题所暗示的,我是一个正在玩数组的初学者。尽管我尽力而为,但我无法正确更改数组中的值?如您所见,数组中只有后5位正确,前3位不正确?为什么会这样?我将在下面发布我的代码,以便大家明白我的意思:

#include <stdio.h>
#include <stdlib.h>
#define MAX_ARRAY 8
void input_array(char anumber[MAX_ARRAY])

    printf("\n\nPlease insert new data to the 1st array with value 5: ");
    fgets(&anumber[0], MAX_ARRAY, stdin);     
    long ret = strtol(&anumber[0], NULL, 10); // Converts char to int
    printf("Converting char anumber = %d to int ret = %d\n", anumber[0], ret);
    printf("\n(Array after): ");
    for (int i = 0; i < MAX_ARRAY; ++i)
    
        printf("(%d) ", anumber[i]);
    

int main(void)

    char arr[MAX_ARRAY] = 5, 8, 2, 9, 1, 7, 4, 3;
    printf("(Array before): ");
    for (int i = 0; i < MAX_ARRAY; ++i)
    
        printf("(%d) ", arr[i]);
    
    input_array(arr); // Function that lets the user change value of "5" inside the array
    return 0;

如果我作为用户输入值“3”,此代码的输出是:

(Array before): (5) (8) (2) (9) (1) (7) (4) (3) 

Please insert new data to the 1st array with value 5: 3
Converting char anumber = 51 to int ret = 3

(Array after): (51) (10) (0) (9) (1) (7) (4) (3)

【问题讨论】:

您试图在同一个变量中包含一个字符串(一个以 null 结尾的字符数组)和一个类型为 char 的元素的数值数组。只是不要那样做。使用单独的变量。 旁注:不用写&amp;anumber[0],你可以写anumber。这两个表达式是等价的。 【参考方案1】:

开场白:

线

long ret = strtol(&anumber[0], NULL, 10); // Converts char to int

错了。特别是// Converts char to int 的评论是错误的。函数strtol 不会将单个字符 转换为int。相反,它会将字符串(即字符序列)转换为long

为了将单个数字字符转换为int,您可以改写以下行:

int number = anumber[0] - '0';

这是可能的,因为 ISO C 要求字符集按顺序存储数字 09

您的程序中实际发生的情况如下:

您正在将数组的 8 个元素初始化为以下值:

(5) (8) (2) (9) (1) (7) (4) (3) 

然后,您使用fgets 输入来自用户的字符串"3\n"。对应的ASCII codes 是数字'3'51 和换行符'\n'10。您用这两个值覆盖数组的前两个元素,并用字符串的终止空字符覆盖第三个元素。

这就是为什么数组在调用fgets 后具有以下值的原因:

(51) (10) (0) (9) (1) (7) (4) (3)

fgets 函数会覆盖前 3 个元素,但保留其余元素不变。

解决问题的正确方法如下:

您似乎只想覆盖数组的第一个元素。因此,您不应将数组用作fgets 函数调用的直接目标,因为该函数将始终写入一个以上的字节(正确使用该函数时)。

解决问题的一个非常简单的方法如下:

void overwrite_first_element_with_input( char arr[MAX_ARRAY] )

    //prompt user for input
    printf( "Please enter new data for the first element of the array: " );

    //write input to first element
    if ( scanf( "%hhd", &arr[0] ) != 1 )
    
        printf( "input error!\n" );
        exit( EXIT_FAILURE );
    

完整的程序如下所示(有一些小的改进):

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

#define MAX_ARRAY 8

void overwrite_first_element_with_input( char arr[MAX_ARRAY] )

    //prompt user for input
    printf( "Please enter new data for the first element of the array: " );

    //write input to first element
    if ( scanf( "%hhd", &arr[0] ) != 1 )
    
        printf( "input error!\n" );
        exit( EXIT_FAILURE );
    


void print_array( const char arr[MAX_ARRAY], const char *tag )

    printf( "%s", tag );

    for ( int i = 0; i < MAX_ARRAY; i++ )
    
        printf( "(%d) ", arr[i] );
    

    printf( "\n" );


int main( void )

    char arr[MAX_ARRAY] = 5, 8, 2, 9, 1, 7, 4, 3;

    print_array( arr, "(Array before): " );
    overwrite_first_element_with_input( arr );
    print_array( arr, "(Array after): " );

    return 0;

这是程序的一些示例输出:

(Array before): (5) (8) (2) (9) (1) (7) (4) (3) 
Please enter new data for the first element of the array: 20
(Array after): (20) (8) (2) (9) (1) (7) (4) (3) 

但是,我不想鼓励您使用scanf 代替fgetsstrtol,因为scanf 有many disadvantages。如果你想解决fgetsstrtol的问题,我推荐以下代码:

void overwrite_first_element_with_input ( char arr[MAX_ARRAY] )

    char line[100], *p;
    long ret;

    //prompt user for input
    printf( "Please enter new data for the first element of the array: " );

    //attempt to read one line of input and verify success
    if (
        //verify that fgets was successful
        fgets( line, sizeof line, stdin ) == NULL

        ||

        //verify that input buffer was large enough to store entire line
        strchr( line, '\n' ) == NULL
    )
    
        printf( "input error!\n" );
        exit( EXIT_FAILURE );
    

    //attempt to convert input to number
    ret = strtol( line, &p, 10 );
    if ( p == line )
    
        printf( "conversion failure!\n" );
        exit( EXIT_FAILURE );
    

    //write the successfully converted number to the array
    arr[0] = ret;

请注意,您必须添加 #include &lt;string.h&gt; 才能使上述代码正常工作。

【讨论】:

哇!这个答案真的值5星!非常感谢您花时间比较 fgets 和 scanf!当一个学徒试图掌握 C 语言的起源时,确实很难……所以再次感谢你! :) @SWEGreven: "Very appreciated when you also took the time to compare both fgets and scanf!" -- 请不要将scanf 的简单性视为始终使用该功能的鼓励。正如我在回答中已经指出的那样,该功能有很多缺点,可能会导致很多错误。如果您想要一个简单的函数从用户那里读取一个数字,而不必处理输入缓冲区和验证输入,您可能需要编写自己的函数来处理所有这些并基于fgets。创建这样一个函数可能需要做很多工作,但它会很容易使用。 @SWEGreven:或者你可以使用我的功能get_int_from_user,我在我的this answer 中发布了该功能。该函数也基于fgets,并执行广泛的输入验证。使用该功能就像使用scanf 一样简单,但不太容易出现错误。虽然它不如scanf 强大,因为它只能从用户那里获取一个数字。 谢谢老兄!欣赏它:) 只是对这条线感到好奇... char line[100], *p; // 为什么这个值为 100?当我将此值更改为 3 时,它需要 1 位,当 4 时需要 2 位,当 5 时需要 3 位,依此类推...您可以输入到元素的最大数字仅为 127。我们可以以某种方式进一步增加与 fgets?或者这是一个问题,因为 fgets 需要有“char”? @SWEGreven: char line[100] -- 通常,在堆栈can be bad 上分配太多内存,因为它可能导致stack overflows(即崩溃)。另一方面,内存缓冲区不应该太小,因为如果用户输入太大而无法放入缓冲区,程序将中止并显示错误消息。因此,大小为 100 字节的缓冲区对我来说似乎是一个合适的折衷方案。但是,如果需要,您可以增加它。【参考方案2】:

你好,我看到你试图将你的数字数组保存在 char 中,所以它可能会导致这种错误。为字符定义两个变量,为数字定义另一个变量。

【讨论】:

正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。

以上是关于允许用户在数组函数中更改“5”的值的主要内容,如果未能解决你的问题,请参考以下文章

PHP 5 Array 函数

使用带符号的char指针更改int数组的值

通过引用 C++ 传递函数数组

Swift 字典内的值访问和更改(涉及数组的字典)

如何获取数组里对象的某个值

如何更改指针变量的值并将更改保留在函数之外而无需通过引用传递?