1

As my title suggests, I am a beginner who is playing a bit with arrays. Although I try to do my best, I am not able to properly change the values inside an array? As you can see, only the last 5 digits are correct in array but not the first 3? Why is that the case? I will post my code below so all of you can see what i mean:

#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;
}

Output from this code if I as user enter value "3" is:

(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)
SWEGreven
  • 13
  • 4
  • You are trying to have a string (a null-terminated arrays of characters) and a numeric arrays of elements of type `char` in the same variable. Just don't do that. Use separate variables. – n. m. could be an AI Nov 25 '21 at 17:53
  • Side note: Instead of writing `&anumber[0]`, you can simply write `anumber`. Both expressions are equivalent. – Andreas Wenzel Nov 25 '21 at 18:06

2 Answers2

0

hello as i see you tried to save your numeric array in char so it can cause this kind of mistakes .define two variable for characters and another for numbers.

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 25 '21 at 19:20
0

Opening remark:

The line

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

is wrong. In particular, the comment // Converts char to int is wrong. The function strtol will not convert a single character to an int. Instead, it will convert a string (i.e. a sequence of characters) to a long.

In order to convert a single digit character to an int, you can write the following line instead:

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

This is possible because ISO C requires that the character set stores the numbers 0 to 9 sequentially.

What is happening in your program is actually the following:

You are initializing the 8 elements of your array to the following values:

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

Afterwards, you input the string "3\n" from the user using fgets. The corresponding ASCII codes are 51 for the digit '3' and 10 for the newline character '\n'. You overwrite the first two elements of the array with these two values, and the third element with the terminating null character of the string.

That is why the array has the following values after the call to fgets:

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

The function fgets overwrites the first 3 elements, but leaves the remaining elements intact.

The correct way to solve the problem is the following:

You seem to only want to overwrite the first element of the array. Therefore, you should not use the array as the direct target of an fgets function call, as that function will always write more than one byte (when using the function properly).

One very simple way of solving the problem would be the following:

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 );
    }
}

The full program would look like this (with some minor improvements):

#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;
}

Here is some sample output of the program:

(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) 

However, I don't want to encourage you to use scanf instead of fgets and strtol, as scanf has many disadvantages. If you want to solve the problem with fgets and strtol, I would recommend the following code:

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;
}

Note that you must add #include <string.h> for the code above to work.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • Wow! That answer is really worth a 5 star! Very appreciated when you also took the time to compare both fgets and scanf! It's indeed hard when a Padawan tries to master the origins of the C language... So thank YOU again! :) – SWEGreven Nov 25 '21 at 20:28
  • @SWEGreven: `"Very appreciated when you also took the time to compare both fgets and scanf!"` -- Please don't take the simplicity of `scanf` as encouragement to always use that function. As already pointed out in my answer, that function has many disadvantages, which can lead to many bugs. If you want a simple function to read a number from the user, without having to deal with handling the input buffer and validating input, you may want to write your own function which handles all of this and is based on `fgets`. Creating such a function may be a lot of work, but it would be easy to use. – Andreas Wenzel Nov 25 '21 at 21:00
  • @SWEGreven: Or you can use my function `get_int_from_user`, which I posted in [this answer](https://stackoverflow.com/a/69636446/12149471) of mine. That function is also based on `fgets`, and performs extensive input validation. Using that function is as simple as using `scanf`, but is less prone to bugs. It is less powerful than `scanf` though, because it is unable to do anything else than obtain a number from the user. – Andreas Wenzel Nov 25 '21 at 21:00
  • Thanks bud! Appreciate it:) Just curious about this line... char line[100], *p; // Why this value is 100? When I change this value to 3 it takes 1 digit, when 4 it takes 2 digits, when 5 it takes 3 digits and so on... And MAX number you can input to the element is only 127. Can we somehow increase this further with fgets? Or is this a issue because fgets needs to have "char"? – SWEGreven Nov 25 '21 at 21:56
  • @SWEGreven: `char line[100]` -- Generally, allocating too much memory on the stack [can be bad](https://stackoverflow.com/questions/21199941/max-amount-one-should-allocate-on-the-stack), as it can cause [stack overflows](https://en.wikipedia.org/wiki/Stack_overflow) (i.e. crashes). On the other hand, the memory buffer should not be made too small, because the program will abort with an error message if the user input is too large to fit in the buffer. Therefore, a buffer with a size of 100 bytes seemed like an appropriate compromise to me. However, if necessary, you can increase it. – Andreas Wenzel Nov 25 '21 at 22:04
  • @SWEGreven: Since you defined the array `arr` to consist of `char` elements, you cannot represent large numbers in these individual elements. On most common platforms, a `char` is able to represent a number between `-128` and `+127`. If you want to represent a wider range numbers, then you will have to use a different data type, such as `int` instead of `char`. An `int` is guaranteed to be able to represent numbers between `-65536` to `+65535`, but on most common platforms, it can represent a wider range. Typically, an `int` can represent numbers between `-2,147,483,648` and `+2,147,483,647`. – Andreas Wenzel Nov 25 '21 at 22:10
  • @SWEGreven: The function `fgets` can only work with arrays of type `char`, not `int`. However, as explained in my answer, you are not supposed to use `fgets` for writing to your main array directly. Instead, you should use a secondary array of `char` elements for storing one line of user input. If you use the function `strtol` for converting that user input, then you will get a `long` as a result, which is guaranteed to be able to represent at least as many numbers as an `int` can. A `long` is guaranteed to be able to represent at least numbers up to `2,147,483,647`. – Andreas Wenzel Nov 25 '21 at 22:17
  • I see! Really thanks for helping me out bud, and also with your very good pedagogy skills! You have lightning fast replies lol!:) As for now I have changed from char to int and it worked flawlessly!:) So ye.. Now I am able to contain numbers up to 99999+ without problem!:) – SWEGreven Nov 25 '21 at 22:41
  • @SWEGreven: Oh, I just noticed that I made a mistake in my numbers above. Instead of `-65536` and `+65535`, it should be `-32768` and `+32767`. Also, I noticed that the negative limits I mentioned are all off-by one, because C does not require [two's complement](https://en.wikipedia.org/wiki/Two's_complement) representation (although most platforms use it and C++ even requires it). However, this is just a technical detail and you don't have to worry about it, since you probably don't understand what I am saying. For most practical purposes, this technical detail does not matter. – Andreas Wenzel Nov 25 '21 at 23:01