Fairly new to C and am trying to parse input from a file. I have no problems getting the operation and address fields but I am getting the value "32767" for the size field.
Here is the code causing issues:
#include <stdio.h>
#include <string.h>
void read_file(char *filename)
{
// operation field, address field, size field
FILE *file = fopen(filename, "r");
char buff[25];
char operation;
long address;
int size;
char *cur_trace = fgets(buff, 25, file);
while (cur_trace) {
// read indivdual fields of trace
// if cur_trace[0] == I then ignore line
if (cur_trace[0] != 'I') {
sscanf(cur_trace, " %c %lx[^,]%*c%u", &operation, &address, &size);
printf("operation: %c\n address: %lx\n size: %u\n", operation, address, size);
}
cur_trace = fgets(buff, 25, file);
}
}
int main(int argc, char const *argv[])
{
read_file("tester.txt");
return 0;
}
and here is the input text I am reading. All lines beginning with 'I' are being ignored.
I 0400d7d4,8
M 0421c7f0,4
L 04f6b868,8
S 7ff0005c8,8
The brackets is not a generic part of the format string, it's part of a specific scanf format code to read strings. It can't just be placed anywhere as a sort of pattern, or used for any other format.
And by the way, reading hexadecimal values will stop at the first non-hexadecimal character, so you don't need it anyway. Just doing e.g.
sscanf(cur_trace, " %c %lx,%u", &operation, &address, &size);
should be enough (if the types of the variables are correct).
The problem is that your format string is not parsing the 3rd argument &size, because of the format string.
The 32767 value is just uninitialized junk.
You need to check that sscanf returns 3 so that all arguments are accounted for.
Related
int main(){
char *inputFile;
char *outputFile;
int numberOfBuffer;
int pageSize;
printf("Enter four inpus, separated by spaces: ");
scanf("%s %s B=%d P=%d", &inputFile,&outputFile,&numberOfBuffer,&pageSize);
readCSV(inputFile,outputFile,numberOfBuffer,pageSize);
return 0;
}
I want to read inputs and run readCSV() method with entering command line to
students.csv test.csv B=5 P=32
that line but my code does not work. Any help?
readCSV() input types
readCSV(char* fileName,char* outputFileName, int numberOfBuffer, int pageSize)
You invoked undefined behavior by passing data having wrong type to scanf(): %s expects char* (pointing at a valid buffer with enough length), but you passed char**.
You should allocate some arrays and pass pointers to them. Arrays in expressions (except for some exceptions) are automatically converted to pointers to its first elements, so you don't need explicit & for them.
Also you should specify the maximum length to read (at most the buffer size minus one for the terminating null-character) to avoid buffer overrun and check if scanf() succeeded to read all required things.
int main(){
char inputFile[1024];
char outputFile[1024];
int numberOfBuffer;
int pageSize;
printf("Enter four inpus, separated by spaces: ");
if(scanf("%1023s %1023s B=%d P=%d", inputFile,outputFile,&numberOfBuffer,&pageSize) != 4){
fputs("read error\n", stderr);
return 1;
}
readCSV(inputFile,outputFile,numberOfBuffer,pageSize);
return 0;
}
Both inputFile and outputFile need to be declared as arrays of char large enough to hold the expected inputs1:
#define MAX_FILE_NAME_LENGTH some-value
...
char inputFile[MAX_FILE_NAME_LENGTH+1]; // +1 for string terminator
char outputFile[MAX_FILE_NAME_LENGTH+1];
Then in the scanf call, do not use the unary & operator for inputFile and outputFile - when you pass an array expression as an argument, it automatically gets converted to a pointer to the first element of the array. You also want to check the result of scanf to make sure you got all your inputs:
if ( scanf( "%s %s B=%d P=%d", inputFile, outputFile, &numberOfBuffer, &pageSize ) != 4 )
{
// bad input somewhere, probably with numberOfBuffer or pageSize,
// handle as appropriate
}
else
{
// process input normally
}
But...
scanf is an awful tool for doing interactive input. It is very hard to make bulletproof, and for stuff like this you're really better off reading the whole thing as a single large string using fgets or something like that, then extracting data from that string.
One thing that may help simplify this for you is that you don't have to read the entire line in a single scanf call. You can read each element individually:
/**
* Start by reading the input file name; we use `fgets` instead
* of `scanf` because it's easier to protect against a buffer overflow
*/
if ( !fgets( inputFile, sizeof inputFile, stdin ) )
{
// error reading input file name, handle as appropriate
}
/**
* Successfully read inputFile, now read outputFile
*/
else if ( !fgets( outputFile, sizeof outputFile, stdin ) )
{
// error reading output file name, handle as appropriate
}
/**
* Now get the number of buffers - the leading blank in the format
* string tells scanf to skip over any leading whitespace, otherwise
* if you have more than one blank between the end of the output file
* name and the 'B' the read will fail.
*/
else if ( scanf( " B=%d", &numberOfBuffer ) != 1 )
{
// error getting number of buffers, handle as appropriate
}
/**
* And finally the page size, with the same leading blank space in the
* format string.
*/
else if ( scanf( " P=%d", &pageSize ) != 1 )
{
// error getting page size, handle as appropriate
}
else
{
// process all inputs normally.
}
Or the memory for them needs to be allocated dynamically, but as you're just learning C that's something to tackle later on.
Most of your issues are caused by misuse of scanf. The solution here is not to fix your usage of scanf, but to avoid it completely. (http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html) Parameters like this should come from the command line arguments, not from the input stream. It is almost always better to leave the input stream clear so that it can be used for collecting data. (eg, write your program as a filter.) For example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static void
check_prefix(const char *a, const char *prefix)
{
if( strncmp(a, prefix, strlen(prefix)) ){
fprintf(stderr, "Invalid argument: %s Must start with, %s\n",
a, prefix);
exit(EXIT_FAILURE);
}
}
static void
readCSV(const char *in, const char *out, int n, int p)
{
printf("in = %s, out = %s, n = %d, p = %d\n", in, out, n, p);
}
int
main(int argc, char **argv)
{
if( argc < 5 ){
fprintf(stderr, "Invalid number of arguments\n");
return EXIT_FAILURE;
}
check_prefix(argv[3], "B=");
check_prefix(argv[4], "P=");
char *inputFile = argv[1];
char *outputFile = argv[2];
int numberOfBuffer = strtol(argv[3] + 2, NULL, 10);
int pageSize = strtol(argv[4] + 2, NULL, 10);
readCSV(inputFile, outputFile, numberOfBuffer, pageSize);
return 0;
}
I need to get argv[1] and argv[2] to different types. I found that I could only use sscanf() once or the next string in argv cannot be retrieved.
Here's my code.
int main( int argc, char *argv[])
{
char t;
float temp;
sscanf(argv[1], "-%[cf]",&t);
sscanf(argv[2], "%f", &temp);
return 0;
}
Only the first sscanf() can get the formatted value.
How could I also get done with argv[2]?
Attempt to save string data in a char leading to undefined behavior (UB).
"%[]" expects to match a character array.
// char t;
// sscanf(argv[1], "-%[cf]",&t);
char t[100];
if (sscanf(argv[1], "-%99[cf]",t) != 1) Handle_Failure();
Recommend:
Add the width limit, like 99, to limit string input. Set to 1 less than the size of t.
Check the return value of sscanf().
This is my code, I don't know how to use fgets after scanf so I am using fgets in the 26th line too but every time I use it, it give me big number(ex.2752100) but I write 2.
Why is it doing it?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
char veta[100];
int line = 1;//tell what line it is on
int found = 0;
char a[100];//put the characters of the line into here
char b[100];
char linesearch[10];//the line you are looking for
FILE *file;//the file pointer
file = fopen("text.txt","r");//point the file
if (file == NULL)
{
printf("file does not exist or doesn't work\n");
return 0;
}
printf("Ahoj, naucim te psat snadno a rychle! \n");
printf("Vyber si uroven slozitosti od 1 do 10:\n");
//scanf("%d", &linesearch);
fgets(linesearch,10,stdin);
printf("\nHledam uroven %d ...\n\n",linesearch);
EDIT:
i have another problem:
while(fgets(a,100,file))
{
if(x == line)
{
found = 1;
printf("level %d found,level %d say: %s",x,x,a);
}
else
printf("reading level: %d\n",line );
line++;
}
printf("\nwrite your string as fast as you can!!");
fgets(veta,40,stdin);
if (strcmp(veta,a) == 0)
{
printf("\nwell done!!!!\n");
}
else
{
printf("\nwrong!!!!\n");
printf("%s", a);
printf("%s", veta);
}
i have small senteces(ex I like my mum and she likes me,etc) i want to compare my text with text from file and get answer if I write it well or not. Bonus points if it tell me how many mistakes i did it will be powerful!.
The fgets() function reads character data from the input. To convert this character data to an integer, use atoi() or a similar function.
fgets(linesearch, 10, stdin);
int x = atoi(linesearch);
printf("\nHledam uroven %d ...\n\n",x);
Your printf statement is printing out the address of the linesearch array, which will seem like a random big number.
If you want to read from stdin, into a char array, using scanf() and then print as an int:
scanf("%s", linesearch); // e.g. reads 1234 into array linesearch[].
printf(" %s ...\n\n",linesearch); // Prints string in array linesearch[].
printf(" %p ...\n\n",linesearch); // Prints base address of linesearch[].
int iNum = atoi(linesearch); // Converts string "1234" to number 1234.
printf(" %d ...\n\n",iNum); // Prints the converted int.
iNum++; // Can perform arithmetic on this converted int.
You are getting a big number from printf because you used %d in the format. The number is the memory address of your character array. To print the character array, update the format to %s.
i'm trying to read strings from a file and into a struct but when i reach strings with two or more words everything i seem to try does not work
data in file
"K300" "Keyboard" "US Generic" 150.00 50
"R576" "16-inch Rims" "Toyota Verossa" 800.00 48
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct partInfo {
char number[6];
char name[20];
char description[30];
double price;
int qty;
}Part;
int main() {
char num[6], name[20], desc[30];
int i=0;
int q;
double p;
char ch;
FILE * in = fopen("input.txt", "r");
Part part1;
fscanf(in, " %[^ ]s", &num);
printf("%s\n", num);
fscanf(in, " %[^ ]s", &name);
printf("%s\n", name);
fscanf(in, " %[^ ]s", &desc); //right here only copy "US and not the Generic"
printf("%s\n", desc);
strcpy(part1.number, num);
strcpy(part1.name, name);
strcpy(part1.description, desc);
fclose(in);
return 0;
}
however when i try to use
fscanf(in, " %[^\n]s", &desc);
it copies the rest of the line
i've been stuck on this for two days can someone please help me
and also how to get rid of the double quotes if that is possible
i tried a different set of code for that and more errors arise :(
In scanf, the expression %[chars] reads the longest string that contains the characters (or character ranges) in the bracket. A caret as first character reverses this: %[^chars] reads the longest string that does not contain any of the characters. Hence, %[^ ] reads stuff up to the next space, and %[^\n] reads stuff up to the next new line.
In your case, where the string is delimited by double quotes, you should read the opening quote, then stuff up to the next quote and finally the closing quote:
res = fscanf(in, " \"%[^\"]\"", name);
This format starts with a space and so discards white space before the first quote. The format string looks ugly because the double quote itself is escaped. To illustrate, this is how the command would look like if your strings were delimited by single quotes.
res = fscanf(in, " '%[^']'", name);
This approach works only if your strings are always enclosed in quotes, even if they don't have spaces.
It is probably cleaner to read a whole line with fgets and then sscanf from that line to catch unmatched quotes. That way you could also scan the line several times - once for a string with quotes, a second time for an unquoted string, say - without accessing the disk more than once.
Edit: Corrected the format syntax, which containes a spurious s and updated the description of the bracket syntax for strings in the first paragraph.
Edit II: Because the OP seems to be confused about how fscanf works, here's a small example that reads parts from a file line by line:
#define MAX 10
#define MAXLINE 240
int main(int argc, char *argv[])
{
FILE *in;
int nline = 0;
Part part[MAX];
int npart = 0;
int res, i;
in = fopen(argv[1], "r"); // TODO: Error checking
for (;;) {
char buf[MAXLINE];
Part *p = &part[npart];
if (fgets(buf, MAXLINE, in) == NULL) break;
nline++;
res = sscanf(buf,
" \"%5[^\"]\" \"%19[^\"]\" \"%29[^\"]\" %lf %d",
p->number, p->name, p->description, &p->price, &p->qty);
if (res < 5) {
static const char *where[] = {
"number", "name", "description", "price", "quantity"
};
if (res < 0) res = 0;
fprintf(stderr,
"Error while reading %s in line %d.\n",
where[res], nline);
break;
}
npart++;
if (npart == MAX) break;
}
fclose(in);
// ... do domething with parts ...
return 0;
}
Here, the line is read in forst from the file. Then, that line (buf) is scanned for the required format. Of course, sscanf must be used instead of fscanf here. On error, a simple error message is printed. This message includes the line number and the field entry where reading went wrong, so the error can be located in the input file.
Note how the sscanf includes maximum field lengths to avoid overflowing the string buffers of the part. A scanning error occurs when the quoted string is too long. It would be nicer to have sscanf read all characters and only store the first 5, say, but that's not how sscanf works. Such a solution requires another approach, probably a custom scanning function.
I'm a bit new to C programming and I keep running into this error. Previously I was using fscanf with %lf because age was a double but since I switched to fgets, I do not know how to get it to accept a double. I am attempting to read into a struct. Here's my relevant code:
double age;
...
while(fgets(Employees[i].age, 10, input) != 0)
gives me this error:
error: incompatible type for argument 1 of fgets
expected 'char *' but argument is of type 'double'
fgets tries reads in a line of text, which isn't ideal for your situation, as you're only interested in the double values.
So instead of using fgets, you'll want to use fscanf with a double format string:
while(fscanf(input, "%lf", &Employees[i].age) == 1)
You may also want to read an entire line of text using fgets() and then try to parse it into values using sscanf().
sscanf() works just like fscanf() and scanf() except that its first parameter is a character string pointer.
Reading an entire line at a time may make it easier to do certain things, such as reporting errors by line number or if a sscanf() fails, trying to convert the line using different format strings.
An example for fun:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
char buffer[1024];
const size_t buffer_size = sizeof(buffer);
int line_number = 0;
while( fgets(buffer, buffer_size, stdin) ) {
size_t len = strlen(buffer);
double value;
line_number++;
if( buffer[len-1] == '\n' ) {
buffer[len-1] = '\0';
len--;
}
if( sscanf(buffer, " %lf", &value) != 1 ) {
fprintf(stderr, "stdin:%d: Unable to read value: \"%s\" makes no sense.\n", line_number, buffer);
exit(EXIT_FAILURE);
}
printf("Successfully read value %lf\n", value);
}
return EXIT_SUCCESS;
}