user4925997
user4925997

Reputation:

Doesn't prints the entire array properly

Here is my code for an atm machine. It first asks the user for card number then Pin and then expiry date.

char card_number[16];
memset(card_number,0,16);
char pin[4];
memset(pin,0,4);
char exp_date[5];
memset(exp_date,0,5);

printf("Enter Card number \n");
//scanf ("%s",&card_number);
fgets (card_number, 16, stdin);
printf("Enter pin\n");
//scanf ("%s",&pin);
fgets (pin, 4, stdin);
printf("Enter expiry date\n");
//scanf ("%s",&exp_date);
fgets (exp_date, 5, stdin);

char data[25];
memset(data,0,25);
char reply[25];
memset(reply,0,25);
int i = 0;
for(i=0;i<25;i++)
{
    if(i<16)
    {
        data[i] = card_number[i];
    }
    if(i>=16 && i<20)
    {
        data[i] = pin[i-16];
    }
    if(i>=20 && i<25)
    {
        data[i] = exp_date[i-20];
    }
}
printf("data: %s",data);

It doesn't takes the input for pin. It just prints out the first 15 char stored in data array. Nothing else. What is the problem in my code?

Upvotes: 2

Views: 78

Answers (3)

Vlad from Moscow
Vlad from Moscow

Reputation: 311126

The problem is that after this code snippet

if(i<16)
{
    data[i] = card_number[i];
}

the array data contains also the terminating zero character '\0' that was copied from card_number and the function printf

printf("data: %s",data);

outputs all characters until this terminating zero is encountered ignoring all other character after it,

Another problem can be that if you entered exactly 16 characters for the array card_number then the new line character will be still in the input buffer. In this case the second call of the fgets will read only this new line character. In this case you should enlarge the arrays by one character.

You should write instead

#include <string.h>

//...

card_number[ strcspn( card_number, "\n" ) ] = '\0';
pin[ strcspn( pin, "\n" ) ] = '\0';
exp_date[ strcspn( exp_date, "\n" ) ] = '\0';

strcpy( data, card_number );
strcat( data, pin );
strcat( data, exp_date );

Or if you do not want to remove the new line character from the strings then exclude these statements

card_number[ strcspn( card_number, "\n" ) ] = '\0';
pin[ strcspn( pin, "\n" ) ] = '\0';
exp_date[ strcspn( exp_date, "\n" ) ] = '\0';

and use only

strcpy( data, card_number );
strcat( data, pin );
strcat( data, exp_date );

Also there is no need to call memset. This can be done by the compiler itself. Just declare the arrays like

char card_number[16] = { '\0' };

or

char card_number[17] = { '\0' };
                ^^^^

And it is a bad idea to use magic numbers. It is better to write for example like

fgets( card_number, sizeof( card_number ), stdin);

Upvotes: 2

Peter
Peter

Reputation: 36637

The last character of card_number will always be a char with value zero ('\0') - that's what fgets() does. Your loop will copy that value over. The %s format will stop when it encounters it.

Your code needs to account for the presence of the '\0' (in all the strings) when copying, and ensure the last one is copied (to avoid undefined behaviour with %s).

If you are expecting exactly 16 characters to be input before the user hits ENTER, and the array is 16 in length, then either fgets() needs to be called twice (to get the total input in two separate pieces) or the buffer needs to be 17 characters or more. fgets() does not remove the newline (if present) so your code needs to deal with it. Read the documentation for fgets().

Upvotes: 1

dbush
dbush

Reputation: 225697

Your arrays that read user input are not large enough to hold the data you're putting in. You need one extra byte for each one to hold the terminating null byte.

char card_number[17];
memset(card_number,0,sizeof(card_number));
char pin[5];
memset(pin,0,sizeof(pin));
char exp_date[6];
memset(exp_date,0,sizeof(exp_date));

Upvotes: 1

Related Questions