I've written a simple config parser using fscanf and now want to add a comment character (#).
My configuration file contains three columns of which fscanf reads and stores in their corresponding arrays. This works well, but I'm a little unsure how to write it so that "if the character read is # then move onto the next line.
I've tried using fgetc but that seems to only read the first character, and it appears to break the logic within my while loop.
I've tried using a modification of "%*[^\n]\n" in my fscanf as:
while(fscanf(fp,"%d\t%f\t%f%*[^#]\n", &a[i], &b[i], &c[i]) != EOF)
but that causes a seg fault.
Config:
#hello and welcome to my config file
1666 -0.314913523 0.999804843 #blah blah
1667 -0.337279687 0.999865966
1703 -0.323162231 0.999774194
1704 -0.311984064 0.99964375
1705 -0.311984064 0.99964375
1706 -0.313381260 0.999671436
1707 -0.313170802 0.999558174
Code:
#include <iostream>
using namespace std;
#define NUM_ITEMS 50
int main()
{
FILE *fp;
fp = fopen("config.conf","r");
if(fp==NULL){
printf("No file.\n");
return -1;
}
int a[NUM_ITEMS];
float b[NUM_ITEMS];
float c[NUM_ITEMS];
int i = 0;
while(fscanf(fp,"%d\t%f\t%f", &a[i], &b[i], &c[i]) != EOF)
{
printf("-> %d %f %f\n", a[i], b[i], c[i]);
i++;
}
fclose(fp);
}
You can use fgets to read each line as a string and then check where '#' appears.
#include <stdio.h>
#define NUM_ITEMS 50
#define MAX_CHAR 500
ssize_t find_index(char *str)
{
size_t i=0U;
for (; *str!='\0'; i++)
{
if (*str++=='#')
{
return i;
}
}
return -1;
}
int main(void)
{
int a[NUM_ITEMS];
float b[NUM_ITEMS];
float c[NUM_ITEMS];
char buff[MAX_CHAR];
FILE *fp;
size_t i=0U;
ssize_t index=0U;
fp = fopen("config.conf","r");
if(!fp)
{
printf("No file.\n");
return -1;
}
while (fgets(buff,MAX_CHAR,fp))
{
index=find_index(buff);
if (index!=-1)
{
buff[index]='\0'; /* Bare in mind this will skip the newline character which fgets appends */
}
if(sscanf(buff,"%d%f%f", &a[i], &b[i], &c[i])==3) /* Checking scanf read 3 numbers */
{
printf("-> %d %f %f\n", a[i], b[i], c[i]);
i++;
}
}
return 0;
}
So find_index() returns the location of the element # was found. Then replaced by NULL terminator.
As Jonathan pointed out in the comments, you can also use the strcspn() function along with strlen() (for error checking) to find the index of #.
Related
I am trying to read values from a file and after some operation write to another file. Here facing a slight issue as I am also trying to save values in a 2D Array and displaying it. My file read and file write are showing correct results but my program throws an exception when it comes to display matrix part.
#include <stdio.h>
#include <ctype.h>
#ifndef NULL
#define NULL ((void *) 0)
#endif
int main(void)
{
FILE *file = NULL; //for file read
FILE *fptr = NULL; //for file write
int mat[182][274];
// code to read and display number from file
// open file for reading
file = fopen("file.txt", "r");
fptr = fopen("file1.txt", "w");
int i = 0,j=0;
fscanf (file, "%d", &i);
while (!feof (file))
{
symbol = fgetc(file);
if (symbol == '\n' || feof(file))
{
fprintf (fptr,"\n");
printf("\n");
}
else{
j=255-i;
mat[i][j]=j;
fprintf (fptr,"%d ", j);
fprintf (fptr," ");
printf ("%d ", j);
}
fscanf (file, "%d", &i);
}
fclose (file);
fclose (fptr);
//Facing issue in this part
int k;
int l;
for (k=0;k<=182;k++)
{
for(l=0;l<=274;l++)
{
printf("%d ", mat[k][l]);
}
}
return 0;
}
Arrays in C start at 0 and end at (array_size - 1).
As you're accessing memory just outside the array, you're most likely experiencing segmentation faults.
To fix this issue, change these lines:
for (k=0;k<182;k++)
{
for(l=0;l<274;l++)
{
printf("%d ", mat[k][l]);
}
}
Notice that I changed the relational operators from <= and >= to < and >, respectively.
Along with that, you may need to fully initialize your array. Odd values may be printed if the array is not initialized. (#Weather Vane).
However, to best be sure if this is the case, we need file.txt and file1.txt.
guys i want to read the text from my file and assign every character to a single element of the array
char A[1000];
FILE * fpointer;
fpointer=fopen("text.txt","r");
i=0;
while(!feof(fpointer))
{
fscanf(fpointer,"%c",&A[i]);
i=i+1;
}
fclose(fpointer);
for (i=0;i<100;i++)
{
printf("%c",A[i]);
}
return 0;
but the problem is that the output is some weird symbols instead of the file's text which is "This is just a test".Why is that happening ?
Possible reasons include:
fopen failed to open the specified file. Fix by checking the return value of fopen.
See Why is “while ( !feof (file) )” always wrong?
You always print 100 characters, but if the file contains less than 100 characters, you're in trouble because you print uninitialized locations of the array, leading to UB. Fix by printing everything starting from zero upto i.
Corrected code snippet:
int i = 0, j = 0;
char A[1000];
FILE* fpointer;
fpointer = fopen("text.txt", "r");
if(!fpointer)
{
fputs("fopen failed! Exiting...\n", stderr);
exit(-1); /* Requires `stdlib.h` */
}
while(fscanf(fpointer, "%c", &A[i]) != EOF)
{
i = i + 1;
}
fclose(fpointer);
for (j = 0; j < i; j++){
printf("A[%d] = '%c'\n", j, A[j]);
}
To expand on the points by #Cool Guy:
In case your files do not contain the null character, you can avoid using another variable to store the number of characters read. If you null terminate your read in characters, you can just print them directly as a string.
You have to make sure that A can hold enough characters. If you expect at most 1000 characters, make sure that A has a size of 1001 bytes to contain the terminating NUL character.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char A[1001] = { 0 }; /* init to NUL, expect at most 1000 chars */
int i;
FILE *fpointer;
fpointer=fopen("text.txt","r");
if(!fpointer) {
perror("Error opening file"); /* print error message */
exit(-1); /* Requires `stdlib.h` */
}
/* read all characters from fpointer into A */
for (i=0; fscanf(fpointer, "%c", &A[i]) != EOF; i++);
fclose(fpointer);
printf("%s\n",A); /* print all characters as a string */
/* alternatively, loop until NUL found */
for (i=0; A[i]; i++)
printf("%c", A[i]);
printf("\n");
return 0;
}
Trying to create a program that takes in a text file and reads it line by line. It then finds the two integers that are on each line and adds them together. It then outputs the new line with the original string and total to a new text file. I need help adding the two integers, getting them from each line, and then putting the new line to a text file.
input text file
good morning hello 34 127
ann 20 45
10 11
fun program and you find the same 90 120
news paper said that 56 11
how do you like 20 5
line number 90 34
Outputs first like would look like: and then continue on
good morning hello 161
Code:
int processTextFile(char * inputFileName, char * outputFileName)
{
FILE *fp = fopen(inputFileName, "r");//open file to to read
char buff[1024];
char *p, *p1;
int num;
while (fgets(buff, 1024, fp)!=NULL)
{
printf("%s\n", buff);
while(scanf(buff, "%*[^0-9]%d", &num)== 1)
printf("%d\n", num);
//fscanf(fp, "%s", buff);
}
return 0;
}
EDIT!!!!::
So now that I've been able to accomplish this. How would I sort it by the number produced? for example:
Time is money 52
here I am 3
21
Would output to a new text file in order like
here I am 3
21
Time is money 52
My version using strcspn() is supposed to work with stdin for input and stdout for output. (so you can do executable <textfile >newtextfile)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[1000];
while (fgets(line, sizeof line, stdin)) {
char *ptr;
size_t x = strcspn(line, "0123456789");
if (line[x]) {
errno = 0;
int n1 = strtol(line + x, &ptr, 10);
if (*ptr && !errno) {
errno = 0;
int n2 = strtol(ptr, &ptr, 10);
if (*ptr && !errno) {
int n3 = n1 + n2;
printf("%.*s%d\n", (int)x, line, n3);
} else {
printf("%s", line); // line includes ENTER
}
} else {
printf("%s", line); // line includes ENTER
}
} else {
printf("%s", line); // line includes ENTER
}
}
return 0;
}
The same version without the error checking
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[1000];
while (fgets(line, sizeof line, stdin)) {
char *ptr;
size_t x = strcspn(line, "0123456789");
int n1 = strtol(line + x, &ptr, 10);
int n2 = strtol(ptr, &ptr, 10);
int n3 = n1 + n2;
printf("%.*s%d\n", (int)x, line, n3);
}
return 0;
}
The approach should be:
open two files, one for input, one for output.
use sscanf() to read the input buffer.
scan the leading string, and then two number.
if previous sscanf() fails, only check for two number.
if either of the above scanning is success, print the sum to the output file.
A sample code, should look like
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *fpin = fopen("ipfile", "r");//open file to to read
if (!fpin)
{
printf("Error in ipfile opening\n");
exit (-1);
}
FILE *fpout = fopen("opfile", "w");//open file to to write
if (!fpout)
{
printf("Error in opfile opening\n");
exit (-1);
}
char buff[1024] = {0};
char str[1024] = {0};
int num1 =0, num2= 0;
while (fgets(buff, 1024, fpin)!=NULL)
{
memset(str, 0, sizeof(str));
//printf("%s\n", buff);
if(sscanf(buff, "%[^0-9]%d %d", str, &num1, &num2)== 3)
fprintf(fpout, "%s %d\n", str, (num1+num2));
else if (sscanf(buff, "%d %d", &num1, &num2)== 2)
fprintf(fpout, "%d\n", (num1+num2));
}
return 0;
}
Note:
The above procedure, is a kind of workaround. If the data pattern in the file changes, lot of changes will be required to maintain a code like that. Instead of usinf sscnaf(), for a better and roubust approach, you should
read the line from file
start tokenizing the input buffer (strtok()) and check for ints as tokens (strtol()).
save the returned tokens and ints seperately.
once the strtok() returns NULL, you print the string tokens and the sum of the ints to the o/p file.
I intend not to change your code completely, so I just added some snippets for improvement.
int processTextFile(char *inputFileName, char *outputFileName) {
FILE *fp = fopen(inputFileName, "r");
FILE *out = fopen(outputFileName, "w");
char line[1024];
if (!fp) {
perror(inputFileName);
return;
}
while (fgets(line, sizeof(line), fp) != NULL) {
int num1 = 0, num2 = 0;
char textPart[1024] = "";
if ( !sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2) {
sscanf(line, "%d%d", &num1, &num2);
}
fprintf(out, "%s %d\n", textPart, num1 + num2);
}
fclose(fp);
fclose(out);
}
Explanation:
I scanned the text file, extracted the text part and the two ints. Since I noticed that the ints are placed at the end of each line, I just used sscanf() for that matter.
sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2);
Here, "%[a-zA-Z' ']%d%d" format specifiers means to get only alphabets and spaces.
Since it will only get letters and spaces, the line "10 11" in your input file won't be put to num1 and num2. Because the code inspects first for a string containing letters and spaces. Since 10 and 11 are not of the qualified types, then the line is just skipped.
That's why I added an if-else statement, which checks if sscanf wrote anything to memory. If sscanf returned 0, then it means that no text part is present. Just digits. So the program will scan the two digits.
if ( !sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2) ) {
sscanf(line, "%d%d", &num1, &num2);
}
I also added file checking for input file. It checks if file doesn't exist or can't be opened by the filestream.
if (!fp) {
perror(inputFileName);
return;
}
Here is the content of output file after execution:
good morning hello 161
ann 65
21
fun program and you find the same 210
news paper said that 67
how do you like 25
line number 124
I need to read in a file that contains text, and then a double for that text. It is simply to get the mean and standard deviation for the set of numbers, so the text that comes before is irrelevant. For example, my input file looks a little like:
preface 7.0000
chapter_1 9.0000
chapter_2 12.0000
chapter_3 10.0000
etc..
In this case, it is finding the mean and std dev for the chapters of a book. I have the section of code below, but I'm not quite sure how to "ignore" the text, and only grab the doubles. At the moment this code prints out zeros and only exits the loop when it exceeds the array limit, which I set as a constant to 20 at the beginning of the program.
FILE *ifp;
char *mode = "r";
ifp = fopen("table.txt", mode);
double values[array_limit];
int i;
double sample;
if (ifp==NULL)
{
printf("cannot read file \n");
}
else
{
i = 0;
do
{
fscanf(ifp, "%lf", &sample);
if (!feof(ifp))
{
values[i] = sample;
printf("%.4lf \n", values[i]);
i++;
if (i>=array_limit) //prevents program from trying read past array size limit//
{
printf("No more space\n");
break;
}
}
else
{
printf("read complete\n");
printf("lines = %d\n", i);
}
}while (!feof(ifp));
fclose(ifp);
}
I think you could use fscanf(ifp, "%*[^ ] %lf", &sample) for reading from your file. The * says to ignore that particular match, the [] specifices a list of characters to match and the ^ indicates to match all characters except those in [].
Or possibly (a bit simpler) fscanf(ifp, "%*s %lf", &sample).
You have two major problems -- you're using feof which is pretty much always wrong, and you're not checking the return value of fscanf, which it what tells you whether you got a value or not (or whether you got to the eof).
So what you want is something like
while ((found = fscanf(ifp, "%lf", &values[i])) != EOF) { /* loop until eof */
if (found) {
/* got a value, so count it */
if (++i >= ARRAY_LIMIT) {
printf("no more space\n");
break;
}
} else {
/* something other than a value on input, so skip over it */
fscanf(ifp, "%*c%*[^-+.0-9]");
}
}
When reading in from a file, it's often best to use fgets to read one line at a time, then extract the parts you are interested in using sscanf:
#include <stdlib.h>
#include <stdio.h>
#define ARRAY_LIMIT 10
#define LINE_LENGTH 128
int main()
{
double values[ARRAY_LIMIT];
int i, count = 0;
double sample;
FILE *ifp = fopen("table.txt", "r");
if (ifp==NULL)
{
printf("cannot read file \n");
return 1;
}
char buff[LINE_LENGTH];
while (fgets(buff, LINE_LENGTH, ifp) != NULL)
{
if (sscanf(buff, "%*s %lf", &sample) != 1) break;
values[count++] = sample;
if (count == ARRAY_LIMIT) {
printf("No more space\n");
break;
}
}
fclose(ifp);
for (i = 0; i < count; ++i) {
printf("%d: %f\n", i, values[i]);
}
return 0;
}
fgets returns NULL if it encounters the end of the file, or if a read error has occurred. Otherwise, it reads one line of the file into the character buffer buff.
The asterisk %*s in the sscanf means that the first part of the line is discarded. The second part is written to the variable sample. I am checking the return value of sscanf, which indicates how many values have been read successfully.
The loop breaks when the end of the file is reached or the count reaches the size of the array.
my text file format is this:
3.2 , 5.6
444.2 , 555
112.34 , 32.3
i want to read the above information present within file name file.txt and store it in two arrays a,b where a will have the float value before the comma and b will have the float value after the comma
Use fgets() in a loop to read each line. Then once you have the line, use sscanf() to scan out the two floating-point numbers, like so:
while(fgets(line, sizeof line, myfile) != NULL)
{
if(sscanf(line, "%f,%f", &a[i], &b[i]) == 2)
{
++i;
}
else
printf("Parse error in %s", line);
}
Note that the return value from sscanf() says how many conversions that succeeded. If it isn't two, we don't want to move forward in the array. Remember to make sure i is initialized to 0 before the loop, of course.
E.g.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define DATA_SIZE 10
int main (void){
char filename[256] = "file.txt";
char input_line[128];
FILE *fp;
float a[DATA_SIZE], b[DATA_SIZE];
int i,j;
if(NULL==(fp=fopen(filename, "r"))){
perror("input file open");
return -1;
}
i=0;
while(NULL!=fgets(input_line, sizeof(input_line), fp)){
if(*input_line == '\n') continue;
a[i]=atof(strtok(input_line, " ,\n"));//ok even this ","
b[i]=atof(strtok(NULL , " ,\n"));
++i;
}
//check print
for(j=0;j<i;++j){
printf("a[%d]=%g, b[%d]=%g\n", j, a[j], j, b[j]);
}
return 0;
}