Avoid code duplication in read/write functions using preprocessor - c

If I have a pair of long functions:
#include <stdio.h>
#include <stdlib.h>
void writeData()
{
FILE *fp; int someVar1 = 1; int someVar2 = 2; int someVar3 = 3;
fp = fopen("results.dat", "a"); // open file
if (fp == NULL) {
printf("I couldn't open results.dat for appending.\n");
exit(0);
}
fprintf(fp, "%d\n", someVar1); // write to file
fprintf(fp, "%d\n", someVar2); // write to file
fprintf(fp, "%d\n", someVar3); // write to file
fclose(fp); // and close
}
void readData()
{
FILE *fp; int someVar1, someVar2, someVar3;
fp = fopen("results.dat", "r"); // open file for reading
if (fp == NULL) {
printf("I couldn't open results.dat for reading.\n");
exit(0);
}
fscanf(fp, "%d\n", &someVar1); // read from file
fscanf(fp, "%d\n", &someVar2); // read from file
fscanf(fp, "%d\n", &someVar3); // read from file
fclose(fp); // and close
printf("someVar: %d %d %d\n", someVar1, someVar2, someVar3);
}
int main(void)
{
writeData();
readData();
return 0;
}
Is there a way I can (ab)use the preprocessor to avoid duplicating read and write code? In other words, is there a way to generate pairs of fprintf(fp, "%d\n", someVar) and fprintf(fp, "%d\n", someVar) in the write() and read() functions respectively?
EDIT: this could equally apply to allocating/deallocating a whole load of memory, e.g. http://pastebin.com/wdAnHfWx. Basically any task which has a lot of code repetition between two complementary, but simple functions.

There is a technique known as X Macros that may fit to your needs. You can check a basic information of how it works in wikipedia (http://en.wikipedia.org/wiki/X_Macro).
Following the wiki explanation, you could create a VAR_LIST, and later expand this list as read or write.
#define MY_VAR_LIST(ENTRY) \
ENTRY(var1) \
ENTRY(var2) \
ENTRY(var3)
#define EXPAND_AS_DEFINITION(my_var) int my_var;
#define EXPAND_AS_WRITE(my_var) fprintf(fp, "%d\n", (my_var));
#define EXPAND_AS_READ(my_var) fscanf(fp, "%d\n", &(my_var));
int my_function_write()
{
MY_VAR_LIST(EXPAND_AS_DEFINITION)
FILE *fp;
fp = fopen("results.dat", "a"); // open file
if (fp == NULL) {
printf("I couldn't open results.dat for appending.\n");
exit(0);
}
MY_VAR_LIST(EXPAND_AS_WRITE)
fclose(fp);
}
int my_function_read()
{
MY_VAR_LIST(EXPAND_AS_DEFINITION)
FILE *fp;
fp = fopen("results.dat", "r"); // open file
if (fp == NULL) {
printf("I couldn't open results.dat for appending.\n");
exit(0);
}
MY_VAR_LIST(EXPAND_AS_READ)
fclose(fp);
}
So to append a new var, you just need to update your VAR_LIST.
I did not tried to compile my code, so there is probably some syntax error, but that is the way it should work.

Why preprocessor? You can to that right in code, something like this
#define READ 0
#define WRITE 1
void do_some_io( int action )
{
FILE *fp; int someVar = 1;
fp = fopen("results.dat", (action == WRITE ? "a" : "r") ); // open file
if (fp == NULL) {
printf("I couldn't open results.dat for io.\n");
exit(0);
}
if ( action == WRITE )
fprintf(fp, "%d\n", someVar); // write to file
else
fscanf(fp, "%d\n", &someVar); // read from file
fclose(fp); // and close
}

Looking at your code, I'd say it's not worth the effort, because there are too many differences in it ("a" vs. "r" in open, different error messages, printf vs. scanf, extra printf). The whole thing will be messy to create and even more messy to undestand if someone will have to read or debug it a year later.
However, for educational purposes:
#define MYFUNC(NAME,VARPART1,VARPART2) \
void NAME () { \
int a= 0; \
VARPART1; \
VARPART2; \
}
// make a print function
MYFUNC(printit, printf("%d", a), return);
// make a scan function:
MYFUNC(scanit, scanf("%d", &a), *global= a);
will create two different functions with one macro, e.g the first will be:
void printit () {
int a= 0; \
printf("%d", a);
return;
}

Related

Am I using typedef structures and arrays correctly to read my file? It is not opening

I'm a beginner in data structures with C, I have taken C programming but I've only touched a little bit on structures in the course and I have not kept up with it.
Anyways, I'm trying to make a program that will read data into an array of structures from a file and print out the contents of the array you have populated. I need help figuring this out.. I'm honestly not too sure if I'm doing this correctly either... :/
Any help is greatly appreciated, and thank you in advance! :)
This is what I tried so far
Here's my code:
FYI - The file I'm trying to open is DataFile.txt
#include<stdio.h>
#include <stdlib.h>
#define SIZE 10
#define ARRAY_SIZE 30
//Struct contains 3 fields, name, age, salary
typedef struct
{
char name[SIZE];
int age;
int salary;
} data;
data a[ARRAY_SIZE];
FILE * fp = fopen("DataFile.txt", "r");
if (fp == NULL)
{
printf("Error %s.\n", strerror(errno));
exit(1);
}
int GetData()
{
int i = 0;
fscanf(fp, "%s", a[i].name);
while(fp && i<ARRAY_SIZE)
{
fscanf(fp, "%d", &a[i].age);
fscanf(fp, "%d", &a[i].salary);
i++;
}
return i;
}
void ShowData( int records_read)
{
//Print text file data on screen
for(int i=0;i<records_read;i++)
{
printf("%s %d %d\n", a[i].name, a[i].age, a[i].salary);
}
}
int main()
{
char name[256];
int i = 0;
int records_read;
//Call the method, getData
i = GetData();
//Prompt and read input from the user
printf("Pick a number from 1 to 10:");
scanf("%d", &records_read);
//Call the method, showData
ShowData(records_read);
fclose(fp);
return 0;
}
The program works if I don't put this part of the code in:
FILE * fp = fopen("DataFile.txt", "r");
if (fp == NULL)
{
printf("Error %s.\n", strerror(errno));
exit(1);
}
BUT the output is just a list of zeros..
A quick answer: At first, try to split FILE * fp = fopen("DataFile.txt", "r"); into two parts as one is the variable declaration FILE * fp = NULL; and the other one is the assignment expression fp = fopen("DataFile.txt", "r");. And then keeps the part of the variable declaration out of all the functions, while moves both the part of the assignment and the if-statement if (fp == NULL){...} into function GetData(). The code might work in this case.

Can't create or write a .txt file in C

I'm trying to create and write to a file in C - for whatever reason this code is running successfully however, doesn't create a file. Please find my code below, any help would be appreciated
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int num;
FILE* fptr;
fptr = fopen("E:\\SAMPLE FILES\sample.txt", "w+");
if (fptr == NULL)
{
printf("Error!");
exit(1);
}
printf("Enter num: ");
(void)scanf("%d", &num);
fprintf(fptr, "%d", num);
fclose(fptr);
return 0;
}
This is a very simple problem.
fptr = fopen("E:\\SAMPLE FILES\sample.txt", "w+");
This is the problem. As you would know, the \ is used to define an escape sequence. Because of that, for an actual \, you have to put it 2 times, like you did at E:\\. The file, instead of creating in SAMPLE FILES, is created at the root directory.
Change it to :
fptr = fopen("E:\\SAMPLE FILES\\sample.txt", "w+");
And your code should work. I tested it an I got output.
Make sure you have a folder named SAMPLE FILES on E: Or else, fopen() returns NULL.
In order to open a file for reading or writing, it is best to at least have some sort of error checking and reporting on it. Please see the basic example below:
#include <stdio.h>
#include <errno.h>
#include <string.h>
extern int errno ;
int main () {
FILE * pf;
int errnum;
pf = fopen ("e:\\sample files\\sample.txt", "wb");
if (pf == NULL) {
errnum = errno;
fprintf(stderr, "Value of errno: %d\n", errno);
perror("Error printed by perror");
fprintf(stderr, "Error opening file: %s\n", strerror( errnum ));
} else {
printf("Enter num: ");
(void)scanf("%d", &num);
fprintf(fptr, "%d", num);
fclose(fptr);
fclose (pf);
}
return 0;
}
At least that way, if you get an error being displayed, you stand a good chance of fixing or dealing with it programmatically.
fptr = fopen("E:\SAMPLE FILES\sample.txt", "w+");
->
fptr = fopen("E:\SAMPLE FILES\sample.txt", "w+");
try

How to dump txt file in C?

#include <stdio.h>
int main(void) {
int name;
int arrival_time;
int size;
int ret;
FILE * fp = fopen_s("C:\\NIA\\data.txt", "rt");
while (1)
{
ret = fscanf_s(fp, "%d %d %d", &name, &arrival_time, &size);
if (ret == EOF)
break;
printf("%d %d %d \n", name, arrival_time, size);
}
return 0;
}
I want to dump my txt file to project but errors are coming out. I'm confused about memory initiation and file format, variables, etc. How can I fix this and print values well?
My txt file is :
Your question lacks the most important information: What is going wrong.
When I compile your code, I get errors for fopen_s. (OK, this is mainly because I use gcc ;) )
The manual tells us how this function looks like:
errno_t fopen_s(
FILE** pFile,
const char *filename,
const char *mode
);
This means, you must use it like this:
errno_t err;
FILE *fp;
err = fopen_s(&fp, "C:\\NIA\\data.txt", "rt");
if (err != 0)
{
fprintf(stderr, "The file was not opened\n" );
exit(1);
}
Or you stick to standard functions and use them as you already tried:
FILE *fp;
fp = fopen("C:\\NIA\\data.txt", "rt");
if (fp = NULL)
{
fprintf(stderr, "The file was not opened\n" );
exit(1);
}
You should definitely add checks for all return values. At least for I/O related functions like fopen and scanf.
Also closing your file would be adviseable. While it is only opened in read mode, it will not cause much trouble as it is closed automatically on program termination, but it is surely good style to do it.
An improved version could look like this:
(As you do not scan strings, there is no benefit using MS non-standard function scanf_s)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int name;
int arrival_time;
int size;
FILE * fp = fopen("data.txt", "rt");
if (fp == NULL) {
perror("File data.txt cannot be opened");
exit(1);
}
while (fscanf(fp, "%d %d %d", &name, &arrival_time, &size) == 3)
{
printf("%d %d %d\n", name, arrival_time, size);
}
fclose(fp);
return 0;
}
This prints the content of your data.txt file on the console.
If dumping you txt file means closing the txt file after using it, you can use the following
fclose(fp);
before the return 0;

Read Values from a file and store it in 2D matrix

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.

Dev-C++ Filehandling

I am using Dev-C++ IDE, and now I am trying to do the file handling.here is my code :
int main(){
FILE *fp;
int b = 10;
int f;
fp = fopen("data.txt", "w");
//checking if the file exist
if(fp == NULL){
printf("File does not exist,please check!\n");
}else{
printf("we are connected to the file!\n");
}
fprintf (fp, " %d ", b) ;
fclose(fp);
printf("Reading from the file \n");
FILE *fr;
fr=fopen("data.txt","r");
fscanf (fr, " %d ", &f) ;
fclose(fr);
printf("the data from the file %d \n", f);
return 0;
}
this code is working in NetBeans, but in Dev-C++, I am just getting the message of "we are connected to the file", but it is not putting the value of "10" into the file. please you know the answer let me know, what should I do?
I can't see anything wrong with your code, but here are some tips
A good habit is to create functions and call these instead of having all inline e.g.
#define FILENAME "data.txt"
void writeFile()
{
FILE *fp;
int b = 10;
fp = fopen(FILENAME, "w");
//checking if the file exist
if (fp == NULL)
{
perror("File could not be opened for writing\n");
}
else
{
printf("File created\n");
}
fprintf (fp, " %d ", b) ;
fclose(fp);
}
void readFile()
{
int f;
printf("Reading from the file \n");
FILE *fr;
fr=fopen(FILENAME,"r");
fscanf (fr, " %d ", &f) ;
fclose(fr);
printf("the data from the file %d \n", f);
}
int main()
{
writeFile();
readFile();
}
then when reading from the file I would suggest you use fgets instead
as it is safer to use since fscanf has a tendency to cause memory overwrites
if values are unexpected.
<- fscanf(fp," %d ", &f );
-> char buf[16]; // some buffer
-> fgets( fp, buf, 10 ); // read as string
-> f = atoi(buf); // convert to int
it works perfectly. No issue with code of IDE. please shift the code in to "My documents" in windows. Try it.... I think its permission issue.

Resources