Facing problems with the atoi function if used repeatedly - c

I have to find the frequency of digits {0,1,2,3,4,5,6,7,8,9} in a given string, I'm using atoi function to convert the character to an integer and I'm having problems with the atoi function when the input string is large (tried this with different test cases of varying length),
for example if the input string is
1v88886l256338ar0ekk
my code works properly and the answer is
1 1 1 2 0 1 2 0 5 0
where the 1st digit indicates the frequency of 0 and so on upto 9,
but if the input string is
9139f793308o0lo66h6vc13lgc697h0f6c32lu84445972k0o0l033od17c083yn5051d6j319hyo8j939n28d913015ns6zx5653x01211x12ch2526o65sg7xw6302141q9203s22l336319ll9yx4b597mr318a7943906750j4u152067nq83ne9f24thu96yd05173l47c803roxci45615f0w53i1sz913jj6za733l73tw6r66mq6p44sfhjr26h8e801z8zlcx2l1e65r2879xj3w3acv216196uq158o663y7oz2i5378v0v5w17762451t424352m23026r9o202i9785382o159e4gu1c8561157z5f1vqs5755465b8u728u956434mv944885li456628a994u7j5278m269n1pk8e46940q834h06il6h447888tr7ig72z10fe09k5g98h9bgt6z40v42s16pt6k3l3v45i83i01b9448g554741w766f2q7v31i085488h060e710p53076c6nm98pi946g8j2n6j8x29qa1ad48172y0u4818121p686bud89741201p54087u56g8scerv9pvhuo09re477zfb224i2c1325bj58jx4bk7b009f6446j5i95474p266i503r670n631x6940gwl71ejbx47imx576129248901765rnpu6l80084t0j1839f5y3409w2n403fu6ogw1170jmb6o5l520vg0703e0
upon reaching the end of the string the atoi function returns wrong values
for example,
my code uses atoi to convert char text to an integer and stores it into int num
at the beginning the function works fine,
text is 9 num is 9
text is 1 num is 1
text is 3 num is 3
text is 9 num is 9
text is 7 num is 7
text is 9 num is 9
text is 3 num is 3
text is 3 num is 3
text is 0 num is 0
text is 8 num is 8
text is 0 num is 0
.
.
.
and upon nearing the very end of the string the function returns
.
.
.
text is 2 num is 2
text is 4 num is 4
text is 0 num is 0
text is 3 num is 30
text is 6 num is 60
text is 1 num is 10
text is 1 num is 10
text is 7 num is 70
text is 0 num is 0
text is 6 num is 61
text is 5 num is 51
text is 5 num is 51
text is 2 num is 21
text is 0 num is 1
text is 7 num is 71
text is 0 num is 1
text is 0 num is 1
text is 3 num is 31
If I replace int num = atoi(&text) with int num = text - '0' my program works perfectly for all test cases,
so can someone please tell me what went wrong and whether I have used the function incorrectly.
Please keep in mind I just want to know why atoi didn't work, hence I'm not looking for replacements for the function.
I've included the snippet of my code below
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
int arr[10] = {0};
char text;
text = getchar();
while(text != EOF)
{
if(isdigit(text))
{
printf("text is %c ",text);
int num = atoi(&text);
printf("num is %d\n ",num);
for(int i =0; i<10;i++)
{
if(num==i)
{
arr[i]++;
//printf("arr[%d] is %d\n", i,arr[i]);
break;
}
}
}
text = getchar();
}
for(int i=0; i<10;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
Thanks in advance for taking the time to read and answer my question

Per the atoi() documentation in the C standard:
The atoi, atol, and atoll functions convert the initial portion of the string pointed to by nptr to int, long int, and long long int representation, respectively.
Note the bolded part.
Given
char text;
this code invokes undefined behavior because the address passed to atoi() is not that of a string:
int num = atoi(&text);
One fix would be:
char text[2];
text[1] = '\0';
// getchar() returns int, not char, in order
// to handle EOF properly
int input = getchar();
while(input != EOF)
{
text[0] = input;
if(isdigit(text[0]))
{
printf("text is %s ",text);
int num = atoi(text);
That ensures that a string (a nul-terminated series of char) is passed to atoi().

you don't need atoi() since you are dealing with single characters, not with strings
getc()returns an int [0 .. 255 for actual characters, -1 for EOF]
you can avoid a lot of {} braces by using break and continue
#include <stdio.h>
#include <ctype.h>
int main() {
int arr[10] = {0};
int text, num;
while(1) {
text = getchar();
if (text == EOF) break;
if (!isdigit(text)) continue;
printf("text is %c ", text);
num = text - '0'
printf("num is %d\n ",num);
arr[num]++;
//printf("arr[%d] is %d\n", num, arr[num]);
}
for(int i=0; i<10;i++)
{
printf("%d ",arr[i]);
}
return 0;
}

Related

How to input stdin strings into array and print them? C Programming

I am practicing how to code C programs, specifically reading stdin statements. The following is a code I wrote to take in the stdin, but I am having trouble inputting them into an array and printing out the correct values.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char* argv[])
{
int count = 0;
char* number = "-n";
int result;
char numArray[50];
result = strcmp(argv[1], number);
if (result == 0) {
printf("Numbers Only\n");
while (!feof(stdin)) {
if (feof(stdin))
break;
for (int i=0; i < sizeof(numArray); i++){
scanf("%s", &numArray[i]);
}
}
}
for (int i=0; i< sizeof(numArray); i++){
printf("%d\n", numArray[i]);
}
}
I am working step by step, so my final code has something to do with manipulating the array and outputting it. However, my question is focusing solely on inputting the stdin into the array first since that is the big step and I will work on manipulating the array later.
The 'Numbers Only' is what I was using to check something out, so do not worry about that at all.
I do not get any errors for the code, but it gives weird outputs. One output is the following:
1 (1, 2, 3 are what I inputted into terminal)
2
3
49
50
51
0
0
0
0
0
32
-56
109
-63
6
127
0
0
-128
80
110
-63
6
127
0
0
20
0
0
0
0
0
0
0
64
0
0
0
0
0
0
0
0
0
-16
-67
6
127
0
0
4
0
Can anyone explain why it outputs those other numbers when my stdin stops after I input 1 2 3 ctrl+D and how I can stop that from happening? I want my array to be the size of how many numbers I input, but I am also having trouble with that if anyone has hints!
Thanks!
The innermost loop is not necessary, only one loop is enough.
When converting with scanf, check its return value.
Also, only print the number of elements actually converted.
Fixing these, a first corrected version is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char* argv[])
{
int count = 0;
char* number = "-n";
int result;
int numArray[50];
int i = 0;
if (argc != 2)
return EXIT_FAILURE;
result = strcmp(argv[1], number);
if (result == 0) {
printf("Numbers Only\n");
while (1) {
int number = 0;
int ret = scanf("%d", &number);
if (ret == 1)
numArray[i++] = number;
if (i == 50 || ret < 1)
break;
}
}
for (int j=0; j< i; j++){
printf("%d\n", numArray[j]);
}
}
Testing:
$ gcc main.c && ./a.out -n
Numbers Only
1
2
3
<CTRL + d here>
1
2
3
Edits from comments: Removed while (!feof(stdin)), expanded error checking to avoid infinite loop and added a check before accessing argv.

C: How can I split the user input of a number and store it into an array of elements?

I have a number, 321197186 which the user inputs. How can I store this number into an array one element at a time. Basically, I am trying to store the 1st digit into 0th element and so on. And then I have to do some computation on that number.
Represent your number as a string, where every character of that string will be the corresponding digit of your number.
There are a plethora of method to read a string, but I suggest you use fgets() like this:
#include <stdio.h>
#include <string.h>
#define MAX_LEN 10
int main (int argc, char *argv[])
{
char number[MAX_LEN];
printf("Enter a number: \n");
fgets(number, MAX_LEN , stdin);
printf("%s\n", number);
return 0;
}
With a for loop, you access the characters (digits) of the string (number) one by one, if you like.
I suggest you also eat the trailing newline that fgets() leaves in the input array, as already explained in Removing trailing newline character from fgets() input.
Alternative solution proposed by bruno#:
scanf("%9s", number);
Read more in C - scanf() vs gets() vs fgets().
Assume you have
int num;
if (scanf("%d", &num) != 1)
{
// Input error
exit(1);
}
// Now the user input is available in num
then you do
#define MAX_DIGITS 32
int digits[MAX_DIGITS] = { 0 };
int index = 0;
while(num != 0 && index < MAX_DIGITS)
{
digits[index] = num % 10;
++index;
num = num / 10;
}
// Now the array digits holds the individual digits
// and index holds the number of valid digits
You can consider this logic in C -
number = 321197186
while(number> 0) - leave if number becomes 0
{
int last_digit = number % 10; - Last digit from the number
printf("%d",last_digit);
number = number / 10; - to get the remaining number.
}
This can be also done in Python as -
number = 321197186
list1 = []
for i in str(number):
list1.append(i)
print(list1)
store this number into an array one element at a time.
Let us take advantage of the input process to have a convenient way to determine the length of input including leading zeros (but not input with a sign, leading spaces) by using "%n" to record the offset of the scan.
Use % 10 to exact the least significant decimal digit of the number.
int number;
int offset;
if (scanf("%d%n", &number, &offset) == 1) {
int a[offset]; // VLA
while (offset > 0) {
a[--offset] = number % 10;
number /= 10;
}
for (int i = 0; i < sizeof a/sizeof a[0]; i++) {
printf("a[%d] = %d\n", i, a[i]);
}
}
Output
a[0] = 3
a[1] = 2
a[2] = 1
a[3] = 1
a[4] = 9
a[5] = 7
a[6] = 1
a[7] = 8
a[8] = 6
But as bruno points out, you just have to check it as a string as an user input with fgets is an array of characters (even if we are talking about numbers).
For more detail:
for(i=0;i<sizeof(array_input);i++){
//Store the char into another array
}

How can I take integer input dynamically and have the loop terminate on pressing enter?

I need to take integer input dynamically and have it terminated as soon as user pressed enter. I never had any problem with this when I'm taking chars as input as I can easily check for newlines and each char is a single character. But here, I can't just take a char input and substract it by '0' as when I enter 10, the char value is 1 and then 0.
Here is a piece of the code I'm using :
int no;
while (scanf_s(" %d", &no) == 1)
{
printf("%d ", no);
}
And here's another piece of code that I use for inputting chars, this works fine for single digit integers too :
char no;
while ((no=getchar()) != EOF && no != '\n')
{
printf(" %d ", no - '0');
}
The scanf loop doesn't terminate when pressing enter but it does take the inputs all correctly. Whereas, the getchar loop terminates correctly but only stores 1 digit integers.
How can I have integer inputs be terminated at blank line user input?
You can use standard function fgets to read the input into a character array and then extract numbers using standard function strtol.
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int is_empty( const char *s )
{
return s[strspn( s, " \t" )] == '\n';
}
int main(void)
{
enum { N = 100 };
char line[N];
while ( fgets( line, N, stdin ) && !is_empty( line ) )
{
char *endptr;
for ( const char *p = line; *p != '\n'; p = endptr )
{
int num = strtol( p, &endptr, 10 );
printf( "%d ", num );
}
}
return 0;
}
If to input the following lines
1
2 3
4 5 6
7 8
9
(the last line is empty that is the user just pressed Enter)
then the output will look like
1 2 3 4 5 6 7 8 9

Input ints separated by whitespace and pass them to an int array

I'm trying to write a program in C where the user inputs a defined number of ints (in this case 5 ints) separated by whitespaces. Then, the input is stored in an int array so, lastly, it can be stored in a char array.
As an example of how the program is intended to work, when it asks for an input:
Input: 20 5 63 4 127
The output of the program should be:
Output: 20 5 63 4 127
This is what I've written so far, but I don't know how to get the input transformed into an int array. Note that I know the length of the input beforehand (in this case, as said above, 5 ints).
// Input: 20 5 63 4 127
// Ask for user input.
// Store the input in this int array.
int input_int_array[5];
unsigned char char_array[5];
for(int i=0;i<5;i++)
{
char_array[i]=input_int_array[i];
printf("%d ", char_array[i]);
}
// Should print: 20 5 63 4 127
You are probably expected to use scanf() to read user input as integers into an array of int:
#include <stdio.h>
int main() {
int input_int_array[5];
// Ask for user input.
printf("input 5 numbers: ");
for (int i = 0; i < 5; i++) {
// Store the input into the array.
if (scanf("%d", &input_int_array[i]) != 1)
return 1;
}
// Output the contents of the array:
for (int i = 0; i < 5; i++) {
printf("%d ", input_int_array[i]);
}
printf("\n");
return 0;
}

Reading numbers from a text file into an array in C

I'm a programming noob so please bear with me.
I'm trying to read numbers from a text file into an array. The text file, "somenumbers.txt" simply holds 16 numbers as so "5623125698541159".
#include <stdio.h>
main()
{
FILE *myFile;
myFile = fopen("somenumbers.txt", "r");
//read file into array
int numberArray[16];
int i;
for (i = 0; i < 16; i++)
{
fscanf(myFile, "%d", &numberArray[i]);
}
for (i = 0; i < 16; i++)
{
printf("Number is: %d\n\n", numberArray[i]);
}
}
The program doesn't work. It compiles but outputs:
Number is: -104204697
Number is: 0
Number is: 4200704
Number is: 2686672
Number is: 2686728
Number is: 2686916
Number is: 2004716757
Number is: 1321049414
Number is: -2
Number is: 2004619618
Number is: 2004966340
Number is: 4200704
Number is: 2686868
Number is: 4200798
Number is: 4200704
Number is: 8727656
Process returned 20 (0x14) execution time : 0.118 s
Press any key to continue.
change to
fscanf(myFile, "%1d", &numberArray[i]);
5623125698541159 is treated as a single number (out of range of int on most architecture). You need to write numbers in your file as
5 6 2 3 1 2 5 6 9 8 5 4 1 1 5 9
for 16 numbers.
If your file has input
5,6,2,3,1,2,5,6,9,8,5,4,1,1,5,9
then change %d specifier in your fscanf to %d,.
fscanf(myFile, "%d,", &numberArray[i] );
Here is your full code after few modifications:
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *myFile;
myFile = fopen("somenumbers.txt", "r");
//read file into array
int numberArray[16];
int i;
if (myFile == NULL){
printf("Error Reading File\n");
exit (0);
}
for (i = 0; i < 16; i++){
fscanf(myFile, "%d,", &numberArray[i] );
}
for (i = 0; i < 16; i++){
printf("Number is: %d\n\n", numberArray[i]);
}
fclose(myFile);
return 0;
}
for (i = 0; i < 16; i++)
{
fscanf(myFile, "%d", &numberArray[i]);
}
This is attempting to read the whole string, "5623125698541159" into &numArray[0]. You need spaces between the numbers:
5 6 2 3 ...
Loop with %c to read the stream character by character instead of %d.
There are two problems in your code:
the return value of scanf must be checked
the %d conversion does not take overflows into account (blindly applying *10 + newdigit for each consecutive numeric character)
The first value you got (-104204697) is equals to 5623125698541159 modulo 2^32; it is thus the result of an overflow (if int where 64 bits wide, no overflow would happen). The next values are uninitialized (garbage from the stack) and thus unpredictable.
The code you need could be (similar to the answer of BLUEPIXY above, with the illustration how to check the return value of scanf, the number of items successfully matched):
#include <stdio.h>
int main(int argc, char *argv[]) {
int i, j;
short unsigned digitArray[16];
i = 0;
while (
i != sizeof(digitArray) / sizeof(digitArray[0])
&& 1 == scanf("%1hu", digitArray + i)
) {
i++;
}
for (j = 0; j != i; j++) {
printf("%hu\n", digitArray[j]);
}
return 0;
}
enter your file input like this
ex:
12
13
22
45
(after every number hit enter)
then run your programm it will run properly

Resources