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

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.

Related

Facing problems with the atoi function if used repeatedly

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

Organizing inputs using a struct - C programming

I am working on making a program that will take in an input parameter 'N' using argv. The value N will then allow the user to enter in N value of lines about a chemical element. For example, one line would look like
1 Hydrogen H other_nonmetals 1.008 1 0 0 0 0 0 0
and using a struct, I will scan and print the input in an organized matter.
I am having two main problems currently. The first problem is scanning in the electron values. In the Hydrogen example above, I would need to scan in 1 0 0 0 0 0 0 and reprint it out in my function print_element. When I do so, only the value 1 is stored. I want all the zeros to be omitted, but if the electron values were 1 0 0 0 0 0 1, then only the 1 would be printed in my function.
The next problem I am having is in my for loops. While looping the function print_element, an extra element with no values will be printed. For example, if the user inputs values for Hydrogen and then Barium, it will print Hydrogen then a completely blank element with all zeros, and then Barium. I cannot figure out how to get rid of the blank element.
#include <stdio.h>
#include <stdlib.h>
#define MAX_ELEMENTS 20
typedef struct{
int num;
char name[MAX_ELEMENTS];
char symbol[MAX_ELEMENTS];
char class[MAX_ELEMENTS];
double weight;
char electrons[MAX_ELEMENTS];
} element_t;
void scan_element(element_t *uno){
scanf("%d %s %s %s %lf %20s", &uno->num, uno->name, uno->symbol, uno->class, &uno->weight, uno->electrons);
}
void print_element(element_t uno){
printf("---------------\n| %d\t%.4f\n| %s\t%s\n| %s\n---------------\n", uno.num, uno.weight, uno.symbol, uno.name, uno.electrons);
}
int main (int argc, char *argv[]){
int i;
if (argc != 2){
printf("ERROR: You must provide exactly one argument to this program.\n");
return 0; }
int N = (int)strtol(argv[1], NULL, 10);
if(N <= 0){
printf("ERROR: Your must provide an integer greater than 0 and less than or equal to 20.\n");
return 0; }
element_t uno[MAX_ELEMENTS];
for(i=0; i<=argc; i++){
scan_element(&uno[i]); }
printf("%d total elements.\n", N);
printf(" had the smallest atomic number.\n");
printf(" had the largest atomic number.\n");
for(i=0; i<=argc; i++){
print_element(uno[i]); }
return 0;
}
Replace for(i=0; i<=argc; i++) with for(i=0;i<N;i++).
To omit the first 0 and everything after it in electrons, add
char*tmp;
if(tmp=strstr(uno->electrons," 0"))
*tmp=0;
to scan_element.
It is faster if you only pass the pointer in print_element, because 4 or 8 bytes will be copied instead of 92.
It is not good to use your current way to get string from input. See How to prevent scanf causing a buffer overflow in C?.

Check if the number is even or odd

My program gives me error(not exactly an error but it just prints error instead of even or odd) even if I put a number or letters. The code works if I remove the isdigit checker(3rd line). I do no know what am I doing wrong. Can someone please help me. Thanks in advance. Here is my code.
int main()
{
int n;
printf("Input an integer\n");
scanf("%d", &n);
if(!isdigit(n))
{
print("error");
return 0;
}
n%2 == 0 ? printf("Even\n") : printf("Odd\n");
return 0;
}
isdigit is not for this purpose.
If you want to check if the input is vaild, one method is to load with %s and use strtol.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void print(const char *s) {
puts(s);
}
int main()
{
char nstr[100] = {0};
int n;
char *e;
printf("Input an integer\n");
scanf("%99s", nstr);
n=(int)strtol(nstr, &e, 10);
if(nstr[0] == '\0' || *e != '\0')
{
print("error");
return 0;
}
n%2 == 0 ? printf("Even\n") : printf("Odd\n");
return 0;
}
man -a isdigit
isdigit()
checks for a digit (0 through 9).
Thus isdigit fails if ascii value of n is not anything but
Oct Dec Hex Char
--------------------------
060 48 30 0
061 49 31 1
062 50 32 2
063 51 33 3
064 52 34 4
065 53 35 5
066 54 36 6
067 55 37 7
070 56 38 8
071 57 39 9
man -a ascii
thus,
if(!isdigit(n))
{
print("error");
return 0;
}
is not an appropriate option. you should probably find some other option to validate n.
The isdigit function checks a character to see if it is in the '0' to '9' range. More specifically, it checks if the ASCII value of the character is between 48 (the code for '0') and 57 (the code for '9').
You're passing an int to this function, not a character, so it's not appropriate to use this function here. Just remove this check and it will work.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n;
printf("Please enter your number\n");
scanf("%d",&n);
if( n%2==0)
printf("The number is even\n");
else
printf("The number is odd\n");
System("pause");
return 0;
}
Check this one.

C - scanf has gone ROGUE

I have this c program where I am inputing a number N followed by N more numbers. For example, I'll enter 100 followed by 100 more numbers. For some reason, after so many inputs the scanf function will stop working properly. It's as if it has stopped taking input and will just continue one with whatever value is in size.
The use case I came up with is 100 1 2 3 4 5 6 7 8 9 10... (repeated ten times). then after three or four times of that I'll type in 100 10 9 8 7 6 5 4 3 2 1... (repeated ten times) and then there will be an infinite loop of print statements.
int main(int argc, const char * argv[]) {
int histogram[10000];
int i;
while (1) {
int *rectPtr = histogram;
int size;
scanf("%d", &size);
if (!size) return 0;
for (i = 0; i < size; ++i) {
scanf("%d", rectPtr);
rectPtr++;
}
printf("%d", 1);
printf("\n");
}
return 0;
}
Distrust infinite loops.
In a series of comments, I said:
You're not testing the return value from scanf(), so you don't know whether it is working. The pair of printf() statements is odd; why not write printf("%d\n", 1); or even puts("1");?
Your code does not test or capture the return value from scanf(), so you do not know whether scanf() is reporting a problem. As a general rule, test the return value of input functions to make sure what you thought happened did in fact happen. You could also print out the values read just after you read them:
if (scanf("%d", rectPtr) != 1)
{
fprintf(stderr, "scanf() failed\n");
return 1;
}
printf("--> %d\n", *rectPtr);
rectPtr++;
Similarly when inputting size. Also consider if (size <= 0) return 0;. And using fgets() plus `sscanf() can make reporting errors easier.
j.will commented:
It is great to know if scanf fails, but I want to know why it fails and prevent it from failing. How do I do that?
I responded:
I understand you'd like to know. With scanf(), the best you can do after a failure is usually to read all the characters that follow up to a newline or EOF, and if you want to know what went wrong, then you print those characters too, because scanf() leaves the last character that it read in the input buffer ready for the next input operation.
void gobble(void)
{
printf("Error at: <<");
int c;
while ((c = getchar()) != EOF && c != '\n')
putchar(c);
puts(">>");
if (c == EOF)
puts("<<EOF>>");
}
The first character in the output is what caused the failure.
See also How to use sscanf() in loops?
Hacking your code to match this:
#include <stdio.h>
static void gobble(void)
{
printf("Error at: <<");
int c;
while ((c = getchar()) != EOF && c != '\n')
putchar(c);
puts(">>");
if (c == EOF)
puts("<<EOF>>");
}
int main(void)
{
enum { MAX_VALUES = 10000 };
int histogram[MAX_VALUES];
int size;
while (printf("Number of items: ") > 0 && scanf("%d", &size) == 1 &&
size > 0 && size <= MAX_VALUES)
{
int *rectPtr = histogram;
for (int i = 0; i < size; ++i)
{
if (scanf("%d", rectPtr) != 1)
{
gobble();
return 1;
}
rectPtr++;
}
printf("size %d items read\n", size);
}
return 0;
}
IMO, you need to check the return value of scanf() for proper operation. Please check the below code. I have added some modifications.
To exit from the program, you need to press CTRL+ D which will generate the EOF. Alternatively, upon entering some invalid input [like a char instead of int] wiil also cause the program to beak out of while() llop and terminate.
I have put the sequence to check first scanf(). All others need to be checked, too.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int histogram[10000] = {0};
int i;
int *rectPtr = histogram;
int size = 0;
int retval = 0;
printf("Enter the number of elements \n");
while ( (retval = scanf("%d", &size)) != EOF && (retval == 1)) {
rectPtr = histogram;
if (!size) return 0;
printf("Enter %d elements\n", size);
for (i = 0; i < size; ++i) {
scanf("%d", rectPtr); //check in a simmilar way to above
rectPtr++;
}
printf("%d\n", 1111111);
printf("Enter the number of elements: \n");
}
return 0;
}
The output of a sample run
[sourav#broadsword temp]$ ./a.out
Enter the number of elements: 2
Enter 2 elements
1
2
1111111
Enter the number of elements: 3
Enter 3 elements
1
2
3
1111111
Enter the number of elements: 9
Enter 9 elements
0
9
8
7
6
5
4
3
2
1111111
Enter the number of elements: r
[sourav#broadsword temp]$
histogram is declared to have size 10000. You say you do 100 1 2 3 ... repeated 10 times. If I correctly understand that uses 1000 slots in histogram.
If you repeat the test more than 10 times, you exhaust histogram and begin to write past the end of array causing undefined behaviour.
So you must either :
reset recPtr = histogram at each iteration
control recPtr - histogram + size <= sizeof(histogram) after reading size (IMHO better)
And as other said, you should always control input operations : anything can happen outside of your program ...

Read numbers from text file and use them as input

I have this text:
0 0 0 0 0 1
0 0 0 0 1 1
0 0 0 1 0 1
0 0 0 1 1 1
I want to read the first 5 numbers from each line and then use them as inputs in a function.
I'm new to c and have only accomplished this code that doesn't do much, if anything really.
int v,o;
FILE *mydata;
if ((mydata = fopen("testinputs.txt", "rt"))==NULL)
{
printf ("file can't be opened'\n");
exit(1);}
fclose(mydata);
How do i complete it?
Thank you.
Well, assuming your file is called "input.txt", then this is all you need to do:
#include <stdio.h>
#include <stdlib.h>
#define LINE_LEN 100
int main ( void )
{
char line[LINE_LEN];
int sum, i, read_cnt, numbers[5];//sum and i are there for my example usage
FILE *in = fopen("input.txt", "r");//open file
if (in == NULL)
{
fprintf(stderr, "File could not be opened\n");
exit( EXIT_FAILURE);
}
while((fgets(line, LINE_LEN, in)) != NULL)
{//read the line
//scan 5 numbers, sscanf returns the number of values it managed to extract
read_cnt = sscanf(
line,
"%d %d %d %d %d",
&numbers[0],
&numbers[1],
&numbers[2],
&numbers[3],
&numbers[4]
);
//check to see if we got all 5 ints
if (read_cnt != 5)
printf("Warning: only read %d numbers\n", read_cnt);//whoops
//just an example, let's add them all up
for (sum= i=0;i<read_cnt;++i)
sum += numbers[i];
printf("Sum of numbers was: %d\n", sum);
}
return EXIT_SUCCESS;
}
With this input.txt file:
1 2 3 4 5
2 2 2 2 2
1 23 2 3 4
12 23
This gives us the following output:
Sum of numbers was: 15
Sum of numbers was: 10
Sum of numbers was: 33
Warning: only read 2 numbers
Sum of numbers was: 35
That should be more than enough to get you started
Here is a small code to read character by character and store only the wanted numbers:
C Code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int c; // Character read from the file
int cpt; // Counter (to get only 5 numbers per line)
int i,j; // Array indexes
int data[4][5]; // 2D integer array to store the data
FILE *f; // File
if ((f = fopen("file.txt", "r")) == NULL) // Open the file in "read" mode
{
printf ("file can't be opened'\n");
exit(255);
}
// Counter and indexes initialization
cpt=0;
i=0;
j=0;
// Read the file till the EOF (end of file)
while ((c = fgetc(f)) != EOF)
{
// If 5 numbers read, go to new line, first index in the data array and to the next line in the file
if(cpt==5)
{
i++;
cpt=0;
j=0;
while(c != '\n' && c != EOF)
c=fgetc(f);
}
// If a number is read, store it at the right place in the array
if(c>='0'&&c<='9')
{
// Convert character to integer (see ascii table)
data[i][j] = c-'0';
j++;
cpt++;
}
}
// Display the array
for(i=0;i<4;i++)
{
for(j=0;j<5;j++)
printf("%d ", data[i][j]);
printf("\n");
}
fclose(f);
}
And here is the output:
0 0 0 0 0
0 0 0 0 1
0 0 0 1 0
0 0 0 1 1
Now you can use your 2D array, for example if you want a variable a to have the 2nd line, 3rd number, you'd do : a = data[1][2]
Don't forget arrays start at index 0
Hope this helps...
It might help you:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
FILE *datafile;
int main()
{
char line[100],*ch;
int count;
datafile = fopen ( "my.txt", "r");
while ( fgets(line , sizeof line , datafile) != NULL )//fgets reads line by line
{
count = 0;
ch = strtok ( line , " ");
while ( count < 5 && ch != NULL )
{
printf("%d ",*ch - 48 );//*ch gives ascii value
//pass to any function
count++;
ch = strtok ( NULL, " ");
}
}
return 0;
}
The above program passes integer by integer.

Resources