Reading a line from a file at a specific point - c

so Im writing a code to get scanf a text file and return a format text message log. I'm stuck wondering how to scan strings from file at a certain point and print every string beyond that point E.X When the file scans the line
"332982000 2055552002 2055551001 7 Mr Webb, can I ask you a question?" I scan the first 4 numbers as integers and scan the rest of the written text into an char array starting at "Mr. Webb".
I tried using a for loop with fscanf to scan into an array but it didnt work. I was also thinking I could use malloc just to save space but I dont know what to put in the sizeof argument. Any help would be GREATLY appreciated!
int posix;
int phone1;
int phone2;
int textsize;
int val, val2;
char line[256];
char text[3000];
int len=strlen(line);
int i=0;
printf("\n\nTime %s %s", argv[2], argv[3]);
printf("\n======================================================================================\n\n\n");
FILE* textfile= fopen(argv[1],"r");
fscanf(textfile, "%d %d %d %d %s", &posix, &phone1, &phone2, &textsize, text);
while( fgets(line, sizeof(line), textfile) ) {
val= atoi(argv[2]);
val2=atoi(argv[3]);
if ( (val==phone1) && (val2==phone2) ) {
printf(" %s ", text); //only prints Mr
text=(char*)malloc(sizeof())//tried malloc but not too sure how to use it correctly
for (i=0; i<len; i++) { //tried using for loop here didnt work.
fscanf("%s", text);
}
sortText(phone1, phone2, textsize, text);
//readableTime(posix);
}
else if ( (val2==phone1) && (val==phone2) ) {
printf(" %s ", text);
sortText(phone1, phone2, textsize, text);
//readableTime(posix);
}
fscanf(textfile, "%d %d %d %d %s", &posix, &phone1, &phone2, &textsize, text);
}
fclose(textfile);
return 0;
}

At first, read the entire file into a malloc'd char array. The fseek and ftell give you the file size:
// C99
FILE *fp = fopen("file", "r");
size_t filesize;
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *filetext = malloc(filesize + 1);
fread(filetext, 1, filesize, fp);
filetext[filesize] = 0;
Then use a buffer for a single line with the size of the entire file so you surely have enough size. sscanf() can be used to read stuff from a string.
int readbytes;
for(int i=0; i < filesize; i+=readbytes) {
char line[filesize];
int posix, phone1, phone2, textsize;
if(EOF == sscanf(
&filetext[i], "%d%d%d%d%[^\n]%n", &posix, &phone1,
&phone2, &textsize, line, &readbytes))
{
break;
}
printf("%d %d %d %d '%s' %d\n", posix, phone1, phone2, textsize, line, readbytes);
}
The format specifier '%[^\n]' means: every character until the next newline character. The format specifier '%n' gives you the number of bytes that have been read with this sscanf call so far, effectively your line size, that you can use to advance the iterator.

Related

C How to use sscanf properly support

I am currently learning reading from files in C.
Anyway, cutting to the chase:
Text file content:
123456 James Doakes; 0
987987 Dexter Morgan; 0
010203 Masuka Perv; 0
int main()
{
char accountNr[ACCOUNTNRSIZE], ownerName[NAMESIZE], enter[3];
int accountBalance = 0;
char filename[] = "breg.txt";
FILE *file = fopen(filename, "r");
if (file != NULL) {
char line[128];
while (fgets(line, sizeof(line), file) != NULL) {
sscanf(line, "%s %[^;] %d ", accountNr, ownerName, &accountBalance);
printf("%s", ownerName);
//fflushstdin();
}
fclose(file);
} else {
perror(filename);
}
return 0;
}
I wrote this to check if the name for instance James Doakes was registered correctly :
printf("%s", ownerName);
But when it prints that out it's like the stdout is still active and I can push Enter and it will type the name again. My goal is to of course be able to sscanff the number, the full name, and the last number as seperate variables. But it obviously doesn't work. I am guessing a \n gets registered as well. Dunno, I am just speculating.
What am I doing wrong? Why? And how do I solve this?
Much appreciated,
Mif
%s %[^;] %d
means a string terminated by white space, optional white space, a sequence of characters that are not ;, optional white space, then a number.
You appear to be not scanning for the actual ; character itself so that, when you try to get the number, the ; in the input stream will cause it to fail. You can see this with:
#include <stdio.h>
#define ACCOUNTNRSIZE 100
#define NAMESIZE 100
int main (void) {
char accountNr[ACCOUNTNRSIZE], ownerName[NAMESIZE], enter[3];
int accountBalance = 0;
char filename[] = "breg.txt";
FILE *file = fopen(filename, "r");
if (file != NULL) {
char line[128];
while (fgets(line, sizeof(line), file) != NULL) {
int count = sscanf(line, "%s %[^;] %d ", accountNr, ownerName, &accountBalance);
printf ("%d [%s] [%s] [%d]\n", count, accountNr, ownerName, accountBalance);
}
fclose(file);
} else {
perror(filename);
}
return 0;
}
which outputs:
2 [123456] [James Doakes] [0]
2 [987987] [Dexter Morgan] [0]
2 [010203] [Masuka Perv] [0]
In fact, even if you change the breg.txt file to be:
123456 James Doakes; 314159
987987 Dexter Morgan; 271828
010203 Masuka Perv; 42
you still get 0 for the account balance because the scanning only successfully reads two items.
Whenever you use one of the scanf-family functions, you should check the return code to ensure it's scanning the correct number of items, as in:
int count = sscanf (line, "%s %[^;] %d ", accountNr, ownerName, &accountBalance);
if (count != 3) {
fprintf (stderr, "Catostrophic failure, count is %d\n", count);
return 1;
}
The fix here is relatively simple, just use %s %[^;]; %d as the format string.
With that change, the output you see is:
3 [123456] [James Doakes] [314159]
3 [987987] [Dexter Morgan] [271828]
3 [010203] [Masuka Perv] [42]
Keep in mind you don't actually need a space before the %d (though it causes no harm). That particular format specifier skips white space before attempting to scan the number.

I am completely new to C programming and keep getting a segmentation fault

This is for a hotel reservation system, that take a .txt file that contains lines of int string string int which it then reads and put into an array of type room... while scanning it keeps giving me segmentation fault... this is for class and i dont want a ready code to leech of but i just dont get why i keep getting segmentation... :/
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int num;
char first[100];
char last[100];
int type;
}room;
int main (int argc, char ** argv){
FILE * myFile;
if(argc !=2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
return EXIT_FAILURE;
}
myFile = fopen(argv[1],"r");
if (myFile==NULL){
fprintf(stderr, "no open!!\n");
return EXIT_FAILURE;
}
// counter to add elements to my array
int i = 0;
char c;
//array of room with the 150 rooms in it...
room * rooms = malloc(150 * sizeof(room));
while ((c = getc(myFile)) != EOF ){
fscanf(myFile, "%d", rooms[i].num);
printf("the room num is: %d", rooms[i].num);
fscanf(myFile, "%s", rooms[i].first);
fscanf(myFile, "%s", rooms[i].last);
fscanf(myFile, "%d", rooms[i].type);
i++;
}
fclose(myFile);
}
Here is what i fixed in my code and worked but it is literally skipping the fist integer in the .txt file that it reads from... it just reads a zero when it should be a 1 so i noticed that the "(c = getc(myFile)) != EOF" was my problem, it is skipping the first integer it is supposed to read :/
while ((c = getc(myFile)) != EOF ){
fscanf(myFile, "%d", &rooms[i].num);
fscanf(myFile, "%s", rooms[i].first);
fscanf(myFile, "%s", rooms[i].last);
fscanf(myFile, "%d", &rooms[i].type);
printf("the room num is: %d and is occupied by %s %s and it is a %d\n", rooms[i].num, rooms[i].first, rooms[i].last, rooms[i].type);
i++;
}
The .txt file's first line is as follows:
1 carri alston 0
In your code
fscanf(myFile, "%d", rooms[i].num);
should be
fscanf(myFile, "%d", &rooms[i].num);
same with the type thing.
Along with that, you should always check the return value of fscanf() to ensure proper scanning.
also, you need to put a check on the value of i so that it should not access out of bound memory.

Read a line and convert to string in c

This is my first post here so dont really know how to post something here with correct format. I have a question on how to read a line from file and read some of the words as string and some as Int.
int check = sscanf(read, "%s %d", string, &integer);
printf("%s, %d", string, integer);
Above is kind of what I did. The input is "oneword 1". What I got is "(null) 4196448". So how can I do it correctly? Thank you
Here is part of my code.
int i;
for (i = 1; i <= 3; i++)
{
char read[MAX_LENGTH_INPUT];
fgets(read, sizeof(read), stdin);
int check2 = sscanf(read, "%s %d", word, &number);
printf("%s %d\n", word, number);
}
So the for loop is to scan three lines in .in file. Can I do that?
Here is the .in file which is the input.
oneword 1
twoword 2
thirdword 3
The output was
(null) 4196448
(null) 4196448
(null) 4196448
Also in your code int check2 = sscanf(read, "%s %d %d", word, &number); format specifier are 3 but arguments 2.
if file contain data like
oneword 1
secondword 2
thirdword 3
fourthword 4
Then
#include <stdio.h>
int main ()
{
FILE *fp = fopen("file", "r");
char read[100];
int integer;
char string[64];
while (fgets(read, sizeof(read), fp) != NULL)
{
int check = sscanf(read, "%s %d", string, &integer);
if (check == 2) {
printf("%s, %d\n", string, integer);
}
else{
printf("Failed to scan all values\n");
}
}
}
And output is
oneword, 1
secondword, 2
thirdword, 3
fourthword, 4
You can modify fgets here to take input from stdin by just replacing fp by stdin in line while (fgets(read, sizeof(read), fp) != NULL)
You are using sscanf
which reads data from char * type and stores them according to parameter format into the locations given by the additional arguments, as if scanf was used, but reading from string instead of the standard input (stdin).
you need to use fscanf and read in your code should be pointer to a FILE.

Converting text to a binary file

I need to convert a text file of the following format to binary:
The first line contains the number of products in the inventory, The following lines contains:
product name '\t' product price '\t' quantity '\n'
(there can be more than one \t between columns)
For every product the binary output file will contain an int representing the length of the product name, the chars that hold the product name, an int representing the price and an int representing the quantity.
Sample input file:
Asus Zenbook 1000 10
iPhone 5 750 22
Playstation 4 1000 0
I have wrote the following code, and I understood that I'm supposed to see the string in plain text while the integers will show up as gibberish (in binary):
int convertTextToBinary(char *fileName)
{
FILE *pText, *pBinary;
int size, i;
char *currProdName;
int currProdNameLen, currQuantity, currPrice;
if (checkFileExists(fileName) == FALSE)
{
printf("- Given file does not exists!\n");
return ERROR;
}
else
pText = fopen(fileName, "r");
// get the number of products in the inventory
fscanf(pText, "%d", &size);
#ifdef DBG
printf("##DBG Successfuly read &size = %d DBG##\n", size);
#endif
pBinary = fopen(strcat(fileName, ".bin"), "wb");
fwrite(&size, sizeof(int), 1, pBinary);
#ifdef DBG
printf("##DBG Successfuly wrote &size = %d DBG##\n", size);
#endif
for (i = 0; i < size; i++)
{
// get product name and name length
currProdNameLen = getProdName(pText, &currProdName);
#ifdef DBG
printf("##DBG %d Successfuly read &currProdName = %s DBG##\n", i+1, currProdName);
printf("##DBG %d Successfuly read &currProdNameLen = %d DBG##\n", i+1, currProdNameLen);
#endif
// get product price
fscanf(pText, "%d", &currPrice);
printf("##DBG %d Successfuly read &currPrice = %d DBG##\n", i+1, currPrice);
// get product quantity
fscanf(pText, "%d", &currQuantity);
printf("##DBG %d Successfuly read &currQuantity = %d DBG##\n", i+1, currQuantity);
// write data to binary file
fwrite(&currProdNameLen , sizeof(int), 1, pBinary);
fwrite(&currProdName, sizeof(char), currProdNameLen, pBinary);
fwrite(&currPrice, sizeof(int), 1, pBinary);
fwrite(&currQuantity, sizeof(int), 1, pBinary);
free(currProdName);
}
fclose(pText);
fclose(pBinary);
return 1;
}
/* This function checks if a file in a given path exists or not by using fopen with "read" argument */
BOOL checkFileExists(char *fileName)
{
FILE *fp;
fp = fopen(fileName, "r");
// file does not exists
if (fp == NULL)
return FALSE;
// file does exists
else
{
fclose(fp);
return TRUE;
}
}
int getProdName(FILE *fp, char **prodName)
{
int nameLen = 0, offset;
// count the length of the product name
while (fgetc(fp) != '\t')
nameLen++;
// allcoate memory for the product name
*prodName = (char*)malloc(sizeof(char)*nameLen);
//checkalloc(&prodName);
// get the cursor back to the original position
offset = -1 * nameLen;
fseek(fp, offset, SEEK_CUR);
// copy product name from text to string
fgets(*prodName, nameLen, fp);
return strlen(*prodName);
}
But the hell, my output file looks like this:
¨ ּּּּּט ¨ ּּּ¯ ¨ ּּּּּּּּ ּּּ«
¨
Which holds no plain text. I have tried changing the fopen argument from "wb" to "w" but I still get gibberish files. What am I doing wrong?
Here you write the pointer and additional garbage instead of the string it points to:
fwrite(&currProdName, sizeof(char), currProdNameLen, pBinary);
You should use:
fwrite(currProdName, sizeof(char), currProdNameLen, pBinary);
In your version you are passing the pointer to the pointer, but you want to pass the pointer itself.
BTW: In your function getProdName(), you should add an additional character, because you are allocating the exact string lenght, but no room for the 0 Byte at the end. This can also cause problems. Also fgets reads one char less. Check the man page for fgets. Instead of using fgets, you can also use fread because you know the length anyway. No additional parsing needed.
update
Change this:
fscanf(pText, "%d", &currQuantity);
to
fscanf(pText, "%d\n", &currQuantity);

Read a file line by line for integers

I just want to output 3 integers from the file. Why this doesn't work? I get -1079184140 and similar.
int main(int argc, char *argv[])
{
FILE* stream = fopen(argv[2], "r");
char line[80];
for (int i = 0; i < 3; i++)
{
fgets(line, 80, stream);
printf("%d \n", line);
}
fclose(streamForInput);
}
I would use sscanf.
int number;
sscanf (line, "%d", &number);
printf ("%d \n", number);
That will pull the first integer on a line. This is not the most secure or robust way, but that is out of scope.
PS:
fclose(streamForInput);
Should be:
fclose(stream);
Hmm. The first problem is:
printf("%d \n", line);
because line is a char[]. But you use a %d to output it, so you output line, which is an address. So printf prints the address of line... instead you coud use printf ("%d", atoi(line));
To print a string, which line is, use %s:
printf("%s \n", line);
Now, if it really were an integer, you could use %d:
int num = atoi(line);
printf("%d \n", num );
What you're seeing is the result of treating a pointer type (which is what a string in C basically is) as an integer type. Since pointers hold memory addresses, that -1079184140 is the actual address the pointer holds, represented as a 32 bit signed integer.
If you know exactly the content of the file (three numbers separated by white space), why not directly read it?
if (fscanf(stream, "%d%d%d", &foo, &bar, &baz) < 3)
// handle error
printf("%d\n%d\n%d\n", foo, bar, baz);
But if you want to read lines, there are already other good answers.
To read a file line by line for integers
void read_file(char *filename, int *readbuff, int size)
{
FILE *fp = fopen(filename,"r");
if(fp == NULL){
printf("Failed to open file %s \n", filename);
return;
}
/*the condition in for loop checks if the integer was read into
readbuff[i] and the readbuff is not overflown*/
for(int i = 0 ; fscanf(fp,"%d\n",&readbuff[i]) == 1 && i < size; ++i);
fclose(fp);
return;
}

Resources