C: integers not printing correctly - c

(Hi guys. I tried searching for the problem I'm having and can't seem to find the solution so far. I'm totally new to programming and am learning C currently, but I am a complete noob so I apologize in advance if I'm making a dumb mistake.)
Here's the problem: Im tryna scan 4 integers and print their values using a while loop. The problem is, the numbers are being printed as crazy long numbers not as the ints that are input. I tried scanning and printing a single int and it printed fine but once I use multiple ints, it starts screwing aroud.
Here's my code:
#include <stdio.h>
int main()
{
int i, n1,n2,n3,n4;
printf("Enter 4 numbers.");
for(i=0;i<4;i++)
{
printf("\n\nEnter number %d: ", i+1);
scanf("%d,%d,%d,%d", &n1,&n2,&n3,&n4);
printf("%d,%d,%d,%d", n1,n2,n3,n4);
}
}

Two things:
the input format given in scanf() should match exactly to the input value for a successful scan. [You need to have ,s in your input]
Always check for the success of scanf() to ensure proper scanning of value. scanf() returns the number of items successfully matched and scanned.
So, you should change your code to something like,
if ( scanf("%d,%d,%d,%d", &n1,&n2,&n3,&n4) == 4)
{
// use n1, n2, n3, n4
}
else
//don't use them, return some error.
Note: Always initialize local variables. Many a time it will save you from the undefined behaviour of read-before-write scenario.
Also, [maybe?] the for loop is not required, as you're scanning all the four numbers at a time.

When you have scanf("%d,%d,%d,%d", &n1,&n2,&n3,&n4);
you must give your input as say
1,2,3,4( commas are needed)
And you said you want to read 4 numbers and you have a scanf that gets the 4 numbers. So there is no need for a loop here. If you want to loop get one number each time inside the loop.

You are looping 4 times, expecting to read 4 numbers in each loop...
Generally speaking, scanf() is a poor tool for parsing any kind of input that might not match the expected format -- and nothing is as fickle as user input. I usually advise reading in whole lines of input (via fgets()), and then parsing them in-memory as appropriate (which, in this case, would probably mean using strtol() and checking how much of the input string was parsed via its second parameter).
This, for example, is much more robust:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define LINELEN_MAX 100
int main()
{
int i;
char input[ LINELEN_MAX ];
char * current;
char * end;
while ( 1 )
{
// whitespaces or commas do not matter,
// and neither does the amount of numbers.
puts( "Enter numbers, or 'q' to quit." );
if ( fgets( input, LINELEN_MAX, stdin ) == NULL )
{
puts( "Error on read." );
return EXIT_FAILURE;
}
if ( *input == 'q' )
{
puts( "Quitting." );
return EXIT_SUCCESS;
}
if ( input[ strlen( input ) - 1 ] != '\n' )
{
puts( "Line exceeded maximum width." );
return EXIT_FAILURE;
}
current = input;
end = input;
while ( *current )
{
if ( !isdigit( *current ) )
{
// skip non-digits
++current;
}
else
{
// parse 1..n digits and print
printf( "%ld\n", strtol( current, &end, 10 ) );
current = end;
}
}
}
}

One reason may be that all your values are being printed onto the same line without any space between them.
Basically you are printing 4 numbers continuously in one line which makes it look like one big number.
I advise you to add a new line format specifier.(If you are a newbie, then you might not understand this, so here are some links that may be useful)
http://www.codingunit.com/printf-format-specifiers-format-conversions-and-formatted-output
There is also the problem that you are reading 4 numbers 4 times , that is you are reading 16 variables in total. For this code , you actually don't need a for loop.

Related

Problem with sscanf not reading the 3 variables i want in C

I have an .txt with "323,John of Sea,11.2" (ignore the ")
and i want to read this and then divide it into 3 variables like: int number1 / char Name[100] / float number2
#include <stdio.h>
int main()
{
int number1;
float number2;
char Name[100],Phrase[100];
FILE *inf ;
if((inf = fopen("Information.txt","r")) == NULL){
printf("Erro!\n");
}
while (fgets(Phrase,100,inf) != NULL )
{
sscanf(Phrase , "%d,%s,%f", &number1 , Name, &number2 );
printf("%d %s %f \n", number1, Name, number2);
}
}
323,John of Sea,11.2
Well the problem is when i compile everthing it gives me 323 John 0.000000 an it should give me 323,John of Sea,11.2 i have tried many things but nothing seems to work. IMPOTANT = It needs to be separeted in 3 varibels 1/ int 1 / chat vector .
Sorry for the english and if you can i would realy apreciate the help.
The problem is that the %s scanf format specifier will only match a single word of input. Therefore, instead of matching John of Sea, it will only match John and leave of Sea on the input stream.
If you want to read all characters up to (but not including) the comma, then you should use %[^,] instead of %s.
Also, you should always check the return value of scanf to verify that it was able to match all 3 arguments, before attempting to use these arguments.
Additionally, I recommend to limit the number of characters written to Name, so that if the input is too large to fit into Name, no buffer overflow will occur (which may cause your program to crash). Since Name has a size of 100 characters, it has room for 99 normal characters plus the terminating null character. Therefore, I recommend to limit the number of matched characters to 99, by using %99[^,] instead of %[^,].
For the reasons stated above, I recommend that you change
sscanf(Phrase , "%d,%s,%f", &number1 , Name, &number2 );
to:
if ( sscanf( Phrase, "%d,%99[^,],%f", &number1, Name, &number2 ) != 3 )
{
fprintf( stderr, "Parsing error!\n" );
exit( EXIT_FAILURE );
}
Note that you will have to additionally #include <stdlib.h> in order to be able to use exit and EXIT_FAILURE.

allocation with char pointer

I am beginner.I have a file which has lines like MONSTER,ERRTU,14,2 . when i tried to read the lines and store them into a dynamic memory allocated array. it seems like it worked at first but then when i tried to print the elements of it later , it doesnt work properly.Is it about using char * ? How can I fix this problem?
here my code is;
char *lines_ptr;
line_ptr=(char *)malloc(line*(sizeof(char)*100));
int i=0;
if (fptr==NULL){
printf("file could not be opened.");
}
else{
//line=number of lines
while(!feof(fptr)){
for(i=0;i<line;i++){
fscanf(fptr,"%s",lines_ptr+i);
printf("%s\n",(lines_ptr+i));
}
}
printf("%s",(lines_ptr));//this part shows me i did something wrong.
}
here is my output;
HERO,DRIZZT,8,3
HERO,CATTIE,6,3
HERO,BRUENOR,10,1
HERO,WULFGAR,12,4
MONSTER,TROLL,4,3
MONSTER,GOBLIN,1,3
MONSTER,UNDEAD,1,1
MONSTER,VERMIN,3,2
MONSTER,MINDFLAYER,10,2
MONSTER,ERRTU,14,2
HHHHMMMMMMONSTER,ERRTU,14,2
why does it happen?
HHHHMMMMMMONSTER,ERRTU,14,2 //why does it happen?
What you do is as follows.
You read to the line buffer, but every time you move the beginning of the text by 1 character.
So when you come back and print beginning of the buffer you will get all the first characters of all previously read lines plus last read line.
you incorrectly use "line_ptr" (and so many other stuff ...).
From what I understand, it's seem you whant to load the entire file into "line_ptr", each file's line being in "line_ptr[i]".
If that so, then I advise you to take your time and do really simple code, and after, make it more complicated.
For instance, dont use malloc : with your current code, it's useless anyway.
Let's say you have a file with NB_LINE line at maximum, each line having NB_MAX_CHAR character at maximum.
#define NB_LINE_MAX 50
#define NB_CHAR_MAX 100
char lines[NB_LINE_MAX][NB_CHAR_MAX];
size_t nbLines = 0;
for (nbLines = 0; fgets(lines[nbLines], NB_CHAR_MAX, fptr); ++nbLines) {
// Nothing to do, fgets do it for us
}
if (!feof(fptr)) {
// problem while reading :/
}
printf("Test :\");
for (size_t i = 0; i < nbLines; ++i) {
printf("%d : %s", i, lines[i]);
}
Does this code work ? If yes, try to improove it by removing NB_LINE_MAX first (then you can have at many line you want in your file, not only 50) and after, try to remove NB_CHAR_MAX (then you can have a line without char limitation).
Misc remark :
sizeof(char) is alway 1, always. So you can delete it from your malloc.
fscanf(fptr,"%s",lines_ptr+i) is dangerous. %s will read at many char it want, so if he read 500 char but lines_ptr can only hold 100 of them, it will write somewhere not good, and you will probably have SIGSEV runtime crash.
while(!feof(fptr)) already say by another, but it's note how you use feof.
There are some mistakes you are doing.First look carefully what you are messing with in the picture.Suppose there are two line in the input hello and world,while taking the first input line_ptr starts from 0,so it will store hello from 0 to 4 but in second line line_ptr is incremented to 1 so it will store world from 1 to 5 and this will go on if more lines are there.
NOTE: Always check the return value of scanf() or fscanf()
For taking line as a input in c, you should use Array of pointers like char *lineptr[MAXLINE];
int readline(char* lineptr[])
{
char line[1000];
for(i=0;i<MAXLINE;i++){
if(fscanf(stdin,"%s",line)){
char *temp=malloc((strlen(line)+1)*sizeof(char));
strcpy(temp,line);
lineptr[i]=temp;
}
}
return i;
}
This function will read a line in a variable line, then it will allocate memory for that line in temp and lineptr[i] will point to that new line.It returns number of lines read.
the following proposed code:
always reads the whole line from the file
properly checks for errors
properly places the read in data in the 'malloc'd array
eliminates the clutter from the code
eliminates the use of a 'magic' number in the code
and now the proposed code
if ( !fptr )
{
perror( "file could not be opened." );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
#define MAX_LINE_LEN 100
//size_t line=number of lines
char *line_ptr = malloc( line * MAX_LINE_LEN ));
if( !line_ptr )
{
perror( "malloc failed" );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
size_t i = 0;
// Note: '%[^\n]' reads to end of line, but not the newline char
// AND appends a NUL byte to the end of the input
// '%*c' reads and discards the newline char
// Note: using the '%*c' requires the last line in the file ends with a newline char
// otherwise the last call to `fscanf()` will 'hang' looking for the final newline
while( i < lines && 1 == fscanf(fptr,"%[^\n]%*c", line_ptr+(MAX_LINE_LEN*i) ) )
{
printf( "%s\n", line_ptr+(MAX_LINE_LEN*i) );
i++;
}

Cannot identify error with code, failing a test case

I have to submit this code as a solution. My code runs perfectly for the given test cases, but I am not able to submit as the code fails one of the tests in the solver. Please help if you can. Any help is appreciated.
Gift Article with Digits
Many customers liked the gift articles with digits inscribed on them and they started buying them for gifting for Birthdays and anniversaries. One customer came to purchase a gift for his mom's 25th wedding anniversary and another customer came to purchase a gift for his son's 18th Birthday. They were disappointed to see only single digits inscribed on the gift items.
Seeing the craze for this kind of gift items, Nisha gave a bulk order for gift items with 2 digit numbers inscribed on them. The parcel arrived when she was busy and her 4 year old son started arranging the newly arrived items in the rack for display. But he has placed all items upside down. She needs to change the orientation of the items.
But to her surprise, she found that some 2-digit numbers were valid when read both ways. [Eg. 68 read upside down would be 89 which is also a valid number] Help Nisha in identifying all such 2 digit numbers.
TestCase
Input 1
18
Output 1
YES
Input 2
46
Output 2
NO
Input 3
a4
Output 3
Invalid Input
C code:
#include<stdio.h>
#include<ctype.h>
#include<string.h>
int main()
{
char str[2];
scanf("%s",str);
int flag=0;
if (strlen(str)!=2)
{
flag=2;goto label;
}
else if (str[1]=='0')
{
flag=1;goto label;
}
for(int i=0;i<2;i++)
{
if(isdigit(str[i]))
{
if((str[i]!='0')&&(str[i]!='1')&&(str[i]!='6')&&(str[i]!='8')&&
(str[i]!='9'))
{
flag=1;break;
}
}
else
{flag=2;break;}
}
label:
if (flag==0) printf("YES");
else if (flag==1) printf("NO");
else if (flag==2) printf("Invalid Input");
return 0;
}
The output after evaluation is as follows:
The program's output is incorrect e.g. for 4a, because you break out of the loop after checking the first digit.
The program's answer is NO when it should be Invalid Input.
the main problem with the code is the following two lines
char str[2];
scanf("%s",str);
When the scanf() input/conversion specifier is "%s" then the function will append a NUL ('\0') char to the input AND the input is not stopped until a white space character is encountered.
White space: space, tab, newline sequence
Therefore, when using the '%s" input/conversion specifier there are two considerations:
the input buffer must be 1 char longer that the max allowed number of input characters
the MAX_CHARACTERS modifier must be used, that is 1 less than the length of the input buffer.
Therefore, those two lines should be:
char str[3]; // allows room for 2 characters plus NUL terminator
scanf("%2s",str); // only allow user to input two characters
however, there are some other problems with the code.
This line:
if (strlen(str)!=2)
does not allow for when there is only a single digit I.E. 1...9 inclusive.
it is a very poor programming practice to use the goto + label sequence. It invariable results in 'spaghetti' code.
this code block:
else if (str[1]=='0')
{
flag=1;
goto label;
}
is not correct as it rejects 10, 20, 30, 40, 50, 60, 70, 80, 90. Note: in C, an array index is in the range 0...(one less than the number of entries in the array) Note: '0' is 0x30 in hex and the NUL terminator is 0x00 in hex.
This line:
for( int i=0; i<2; i++ )
is making the assumption that all the 'ages' are 2 digit numbers. That excludes the ages 1...9 inclusive. Suggest:
for( size_t i=0; i<=strlen(str); i++ )
Note: strlen() returns a size_t, not an int and returns the index to the NUL char
flag = 2; // initialize to indicate invalid input
if( strlen( str ) )
{ // then some characters entered by user
for( size_t i=0; i<strlen( str ); i++ )
{
... // check for invertible digit
... // check for non digit
}
}
switch( flag )
{
case 0:
printf( "YES\n" );
break;
case 1:
printf( "NO\n" );
break;
default:
printf( "Invalid Input\n" );
break;
} // end switch
// Note: on modern C compilers,
// when the returned value from 'main()' is always 0,
// then no 'return 0;' statement actually needed
return 0;
} // end function: main
However, the above code snippet does not handle when the user input contains 1 invertible digit and 1 non invertible digit nor when any of the user input is not a digit. I'll let you supply the appropriate logic. The above should get you started in the right direction.
You can try the below code!
#include<stdio.h>
#include<string.h>
void main(){
char str[2];
int a,b;
scanf("%s",str);
a=str[0];
b=str[1];
if(strlen(str)!=2)
printf("Invalid Input");
else if(str[0]=='0')
printf("NO");
else if((a>47&&a<58)&&(b>47&&b<58))
{
if(((str[0]=='1')||(str[0]=='6')||(str[0]=='8')||(str[0]=='9'))&&((str[1]=='1')||(str[1]=='6')||(str[1]=='8')||(str[1]=='9')))
printf("YES");
else
printf("NO");
}
else
printf("Invalid Input");
}

bug when reading integers from a text file in C

I am a little bit desperate as I wasted my last 4 hours looking for a solution for a simple/stupid thing. I have a project in school in which I must read integers from a text file and then calculate the maximum of them. The thing is that these numbers are not necessarily separated by spaces, but also tabs ( \t ) or newlines (\n). I use the fscanf function to read my integers, but the problem is that after the last number I have a space in my file, so it reads 2 times the last number(I do not know why). Normally one would say "Just delete that space", but my teacher is going to test the program in several manners, and he warned us that the program must be robust (we have to be able to manage the spaces, \t, \n so we can read correctly the numbers, so this is why he left on purpose a space after the last number). Here is my code with the sample text:
FILE* file = NULL;
int *t = NULL, *new_size = NULL;
int temp, count;
file = fopen(argv[1],"r");
do
{
fscanf(file,"%d",&temp);
count++;
new_size = (int*) realloc (t, count * sizeof(int));
if (new_size != NULL)
{
t = new_size;
t[count-1] = temp;
}
else
{
free(t);
puts("Erreur d\'allocation memoire!\n");
exit(1);
}
} while(!feof(file));
fclose(file);
printf ("Numbers read\n:");
for(i = 0; i < count; i++)
{
printf ("%d ", t[i]);
}
And my argument is a file named data.txt which contains: 3 1 7 0 4 9 6 150 and a \n at the end. So basically, my program reads the first 8 integers, and after that, since it is not EndOfFile, it still reads the last one (150) again. So my output is :
Numbers read:
3 1 7 0 4 9 6 150 150
Could anyone tell me what I should do in order to make my program more robust? I need to manage the same type os error if there is a space at the end, or even a tab (\t).
Any help would be appreciated!
Check the return value of fscanf
if (fscanf(file,"%d",&temp) != 1) break;
and break out of the loop if it doesn't find a number anymore. fscanf returns the number of successful conversions, and that should be used for error checking and handling.
Use the result of fscanf(), which returns the number of assignments made, as the terminating condition of the loop. After the loop check that EOF was reached and the loop did not terminate due to some other failure.
If the numbers are separated by a space, then you can read a space with fscanf and then an integer.To make the program robust, always see if fscanf fails.If it fails then stop reading integers, else continue.
bool good=true;
while(good)
{
char separator;
if(fscanf(file,"%c",&separator)==1)
{
if(separator!=' ' && separator!='\t' && separator!='\n')
{
fprintf(stderr,"Illegal character found in file");
// You can choose if break the loop setting good to false, or
// if to continue, this depends on your assignment
}
if(fscanf(file,"%d",&temp)==1)
{
< Push temp to your list/array >
}
else
{
good=false;
}
}
else
{
good=false;
}
}

Read in Numbers from a File in C

I have a file called points.dat which reads something like:
5
2 5
-1 18
0 6
1 -1
10 0
The first number is how many ordered pairs there are. The next 5 lines contain those ordered pairs. What can I do to read in the first number, determine how many points there are (from here I can malloc an array of structs to store the points in).
My problem is that fgetc doesn't really do the job here. What if the first number is two digits? Say the first number is 10. fgetc will only retrieve the '1'. Also, fgets doesn't really work, since you need to supply it the length of the amount of characters you want to read in. The same applies for fscanf.
The real trouble comes in when it's time to retrieve the ordered pairs. I have no idea how to do this either. My only thoughts so far is look at a line: if it sees non-spaces or non-'\n's, it will read in the number as the x coordinate of point 1. Loop. Get y coordinate. Once it hits a '\n', it will now move on to the next line, and begin looking for values to store in the next struct in the array of structs.
(While doing this, I also need to be sure atoi can convert all of these into integers... ).
If anyone has any ideas to help, they are appreciated.
For the first line use int numValuesRead = fscanf(file, "%d", &totnums);
Then, use numValuesRead = fscanf(file, "%d %d", &num1, &num2); to read the other lines.
fscanf returns the number of value read. You should always check it.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x, y;
} Point;
int main ()
{
int numOf;
Point *myPoints = NULL;
FILE *myfile = fopen ("myfile.txt","r");
if (myfile == NULL)
perror ("Error opening file"); //or return 1;
else
{
fscanf(myfile, "%d", &numOf);
myPoints = (Point *)malloc(sizeof(Point) * numOf);
while ( !feof (myfile) && numOf-- )
{
fscanf(myfile, "%d %d", &(myPoints[numOf].x), &(myPoints[numOf].y));
}
}
fclose(myfile);
//Do stuff with array
free ((void *)myPoints);
getchar();//Press enter to close debugger etc.
return 0;
}
Sorry for the delay.

Resources