reading string with spaces and then integers from same line in file - c

so the title says everything and i created a VERY simple code just to test this, and i cant get it to work.
The file has one line and it is "asd dsa:1 2 3"
i want to store "asd dsa" in a string variable, and each number in a different int variable.
this is the code:
#include<stdio.h>
int main(){
FILE *fp;
fp=fopen("file.dat","r");
char aa[20];
int a, b, c;
fscanf(fp, "%[^:]%d %d %d", aa, &a, &b, &c);
printf("%s %d %d %d\n", aa, a, b, c);
return 0;
}
and the output is
asd dsa 21911 1313271752 32720
so it is reading only the string.

I highly suggest in the future to learn how to debug your code. To be honest, I did not found the solution right at the top so I copied the code, and ran in on my machine and I got the wrong output, like you. Then, I debugged my code and I noticed the string is read correctly, and the numbers remain untouched. To make sure, I created a variable to hold the return value from scanf, and indeed it was 1 since only the string was getting the input.
I then first tied to add a space between %[^:] and %d, but to no avail. Then I looked at the file again, and the string I got on aa variable and noticed the : was in the file, but not in aa. Where did it go? nowhere, it was still in the buffer waiting to be read. In order to "skip" it, you could just add : sign after %[^:], so the command would "eat it", and after doing it on my machine it worked.
The short answer, is to change the scanf line to:
fscanf(fp, "%[^:]:%d %d %d", aa, &a, &b, &c);
The long answer, is to learn how to debug you code correctly, It took my less than 2 minutes to figure it out and I'm sure that if you tried yourself, you could find the solution too.
Of course if you try debugging yourself with no avail, you are always welcome to open a topic!

Related

Performance - C program takes way longer to run on VS code (windows 10)

I have just installed visual studio code & after watching some basics, I have written a simple C code to calculate area of rectangle. But, when I run the code its taking too long to execute.
My system configuration are 4gb RAM, i3 - 5th gen (poor boi) Here is the code:
#include <stdio.h>
int main()
{
int l;
int b;
printf("enter the length of rectangle in an integer value");
scanf("%d ", &l);
printf("enter the breadth of rectangle in an integer value");
scanf("%d ", &b);
printf("the area of rectangle is %d", l * b);
return 0;
}
Change scanf("%d ", &l); to scanf("%d", &l); and scanf("%d ", &b); to scanf("%d", &b);.
A space in a format string tells scanf to read from input until a non-white-space character is read. So, after scanf("%d ", &l);, the program continues reading input until you type something such as the next number. If you do type that next number, then scanf("%d ", &b); reads it and then continues reading until it sees another character that is not a space. As long as you do not type anything, or type only spaces and returns/enters and other keys that generate white space characters, the program continues waiting.
Removing the spaces eliminates this.
The program is not “taking too long to execute.” In fact, the program is waiting for user input, so it is just waiting, not executing. Because it did not complete, you concluded it was taking too long to execute. Instead of reporting a conclusion, you should have reported the observed behavior: After typing input, there was no visible activity by the program.
Skipping spaces before performing a conversion is built into most scanf conversions, such as %d. Only include a space character in a format string where you want to skip spaces that would not be skipped normally, such as before a %c conversion, which does not have the automatic skipping built in.
Also, in printf("the area of rectangle is %d", l * b);, add a new-line character at the end, printf("the area of rectangle is %d\n", l * b);. (This ensures the prompt printed by a command-line shell after the program finishes executing is on a new-line, so it will not be confused with the program output. C is designed to end lines of output with new-line characters, so you should make it a regular practice.)
Alright guys, I found the solution. The first thing I want to apologize is that the code is not taking too long to execute. The code is actually executing but there was no visible activity. Everything in the code is just perfect. The mistake I made is I didn't change one setting in VS Code. I use code runner extension to run my codes [that's the most popular]. I have to go in File --> Preferences --> Settings --> Type 'code runner' in the search bar --> check the setting given in this image - https://drive.google.com/file/d/1QwB2NjKpYX7M0b5w55sqy4oMVAOk_IK2/view?usp=sharing
Lot of people were trying to figure out a mistake in the code, but there is nothing wrong with it. Code runner was not able to run in the terminal, so there was no activity to take any user input - due to read only text editor. After changing that setting I was able to give user input directly in the terminal.
Credit for the solution - https://www.youtube.com/watch?v=Si8rN5J249M
EDIT: There is a mistake in my code also lol, which is mentioned in another answer - Really appreciate it Eric Postpischil

Why does code yields no results on this char comparison?

Evening, sorry for beginner question but I have to do a code that receives 7 salutations in different languages, compare to a database, and, if they match, tell which language the salutation was on, if they don't, tell the user the language is unknown.
I think i understood the problem, but my code below doesn't show any results and just closes, can someone tell me why? I know it is very sketchy coding but cant find exactly the mistake. (Telling me a substitute for the multiple variables inside scanf would be much appreciated too).
#include<stdio.h>
#include<string.h>
int main(){
char en[7][15];
char id[7][15] = {"HELLO","HOLA","CIAO","HALLO","BOUNJOUR","ZDRAVSTVUJTE","."};
char re[7][15] = {"INGLES","ESPANOL","ITALIANO","ALEMAN","FRANCES","RUSO","NLS"};
scanf("%s %s %s %s %s %s %s",en[0],en[1],en[2],en[3],en[4],en[5],en[6]);
int i = 0,j=0,m=1,k=0;
while(i<8){
for(j=0;j<7;j++){
m=strcmp(en[i],id[j]);
if(m==0 || j==6){
strcpy(en[i],re[j]);
k=i+1;
printf("Caso %s: %s /n",k,en[i]);
break;
}
}
i++;
}
}
Thank you
The problem is your printf function. You are using %s format specifier for k instead of %d. Just change that line to this:
printf("Caso %d: %s \n",k,en[i]);
Also, the while condition i<8 should be changed to i<7 since there are 7 cases and not 8.
As for the scanf, don't think it's much of an improvement but you can use a for loop as well.

Simple C program won't run. Crashes in CMD

I'm new to programming in C and I'm trying to build and execute my first programs. My first program was Hello, World printed in the CMD like many of you. It worked great. Now it's onto bigger and better projects though and I'm having a weird issue.
I'm trying to make a basic addition calculator using standard IO operations (scanf and printf) and it won't function properly.
My program asks for 2 numbers to be input by the user and it will then display the output of said calculation. The program executes flawlessly until the scanf expression comes into play. After I input my 2 numbers to be added the CMD prompt just closes without warning and never spits out an answer or the text I have to be displayed afterward.
I tried multiple solutions to fix this problem including copying and pasting the source code directly from the website I was learning from, even their perfect code nets the same outcome..just a crash before an output is displayed. I'm posting today because I'm wondering where my issue is coming from because I'm just not sure why this program won't execute as it's supposed to. Thanks in advance and heres the code I'm working with:
#include <stdio.h>
int main()
{
int a, b, c;
printf("Enter two numbers to add\n");
scanf("%d%d", &a, &b);
c = a + b;
printf("Sum of the numbers = %d\n", c);
return 0;
}
Once console application returns from main method, the associated console window closes automatically. I assume you are using Windows OS. In that case add a system("pause"); before your return 0; statement.
For platform independent solution you can just show a prompt to user and wait for a key press before returning from main. As #chux pointed out in comment any character remaining in input buffer (enter from scanf in this case) must be cleared.
#include <stdio.h>
int main()
{
int a, b, c;
printf("Enter two numbers to add\n");
scanf("%d%d", &a, &b);
c = a + b;
printf("Sum of the numbers = %d\n", c);
//clear input buffer
int d;
while ((d = getchar()) != '\n' && d != EOF) { }
printf("Press ENTER key to Continue\n");
getchar();
return 0;
}
CMD prompt just closes without warning and never spits out an answer
Seems like you are opening a new terminal on Windows machine. I compiled the code and it works. Your program closes just after printing the answer so you simply cannot see it. Stop it artificially before the end. To prove it add the following line directly before return:
scanf("%c", &a);
This will result in stopping the program and waiting for input. You will need to enter another number which will essentially be ignored but will stop the program so you can see the output. This is not a good target solution though due to you need to enter some characters to go on and exit but it proves the point :)

Regarding about file input and output in C

I normally don't ask questions on here unless I'm really stuck! I was wondering if anyone can please explain why my code prints out a '5 47'. I understand why there is a 5, but not why there is a 47? I looked up the ASCII values for blankspace (32) and I tried changing the second letter to e, f, g, for example but the output remains '5 47' unchanged.
In general, when I use fscanf(fp, "%d", &variablename), does the fscanf skip over miscellaneous characters? For example: in my file test.txt I had "5 hello 6 ben jerry\n". How would I scan in the 5 and the 6? Would fscanf(fp, "%d %d", &test1, &test2) scan in the 5 and 6, skipping over the word "hello"?
Here is my simple code I am using to test output:
int main(int argc, char *argv[]) {
int blah, test;
FILE * fp;
fp = fopen(argv[1], "r");
fscanf(fp, "%d %d", &blah, &test);
printf("%d %d\n", blah, test);
return 0;
}
My file I am using as argv[1] contents:
5g
P.S. is FILE *fp an actual pointer to each character/number and does it work as a placeholder when it scans through the file? Is that why we need rewind(fp) once it hits the end of the file?
The operator %d looks for an integer, not a character. Because g is a character, not an integer, %d is getting confused and the output will not always be 5 47. The 47 could be anything. it could be 5 7, 5 23 etc. This is because the fscanf is not reading a second number, so no value is being assigned to test. Therefore, test remains at the value which was sitting in that piece of memory when the program was initiated.
To fix this, replace %d with %c and change the type of blah and test to int. Also, as WhozCraig said, it is good practise to check the return value of fscanf to check that two values have been found. This way, you can be sure that everything you're looking for has been found.
Note that the scanf() family of functions stop reading when they come across a character that is not expected by the format string. The unexpected character is left in the input for the next input operation to process.
If you want to read two integers that are definitely separated by a 'word' that is not an integer, then you will need to skip the word. If you don't know in advance what the word will be, you need to use assignment suppression (see the POSIX scanf() page for lots of information).
Hence, your code to read the two integers from input containing
5 hello 6 ben jerry
should be:
if (fscanf(fp, "%d %*s %d", &blah, &test) != 2)
…Oops; format error?…
Note that the code tests that it got the expected result. However, if you don't know whether there'll be a word between the two numbers, you are much better off using fgets() and sscanf() because you can try different parses of the same line:
char buffer[4096];
while (fgets(buffer, sizeof(buffer), fp) != 0)
{
if (sscanf(buffer, "%d %*s %d", &blah, &test) == 2)
…got two numbers with a word — let's go!
else if (sscanf(buffer, "%d %d", &blah, &test) == 2)
…got two numbers but no word — let's go!
else
…didn't recognize the format…
}
One of the major advantages of this is that you can report the error in terms of the complete line of input, rather than just the part that fscanf() didn't manage to work on.
Your last question, about a FILE *, is not a pointer to each character in the file. It is a handle which allows you to invoke functions that take a file pointer argument to read from or write to the associated file. However, you can't use indexing based on the file pointer (so fp[1024] does not identify the character at offset 1024 in the file or anything useful like that). If you want that sort of behaviour, you need a memory-mapped file (mmap() for POSIX systems).

Hard-coded string in the format of scanf

I'm trying to match lines with a format like "point %d %d". So I only need to two those two integers, then the "point" is hard-coded in the format string. As I understand reading Linux man pages of scanf, this should work correctly.
The next code, the way I want to use, the first call to scanf works, but the next calls scanf return with an error code and never take more numbers from the stdin (scanf doesn't block waiting for more input from stdin):
for (;;)
{
scanf("point %d %d", &x, &y);
printf("=> point %d %d\n", x, y);
}
In this way, everything work as expected:
int x, y;
char s[10];
for (;;)
{
scanf("%s %d %d", s, &x, &y);
printf("=> point %d %d\n", x, y);
}
Any suggestion about what could I am misunderstanding?
Thanks.
There's still unconsumed data such as end-of-line characters in stdin that make the upcoming scans to stop with a non-match. In the second version this end-of-line data gets consumed by the %s.
I suggest you fgets to a buffer first and then sscanf it. And do check your return values.
My guess is that you are not giving it proper input. For example this input will not work:
4 5
This should work:
point 4 5
You didn't mention the error code, but it is probably saying that you didn't follow the format correctly (i.e. put in point before the numbers).
As a good programming practice you should flush the standard input before taking inputs from user.

Resources