I am writing a program which should do multiple things including prompting the user for the name of the input file which I have done, but I am having troubling implementing a process where the program processes each line from a file, storing it as a struct data structure, finally using the malloc, calloc commands it will store all the valid records in memory to be validated. So any help on how to do this would be helpful.
#include <stdio.h> //library including standard input and output functions
#include <stdlib.h> //library including exit and system functions used below
#include <string.h> //library including string functions used
struct packet{
int source;
int destination;
int type; // Varibles for the structure
int port;
char data[50];
char * filename;
};
int main ()
{
printf("**************Details*******************************\n");
printf("*****Student name: ***********************\n");
printf("*****Course name: *******\n");
printf("*****Student ID: ************************ \n");
printf("\n");
// The program must prompt for the name of the input file. If it doesn't exist the program should stop with an error message
FILE *DataFile;
char filename[10] = { '\0' } ;
char DataLine[70];
printf("Enter the filename you wish to open\n");
scanf("%s", &filename);
if (( DataFile = fopen(filename, "r")) == NULL)
{
printf ("*****file could not be opened. : %s\n", filename);
exit(1);
}
// Read the data from this file
char *fgets(DataLine, 70, (FILE) *DataFile);
system("pause");
return 0;
}
Here is the text file the program should take the data from
0001:0002:0003:0021:CLS
0001:0010:0003:0021:CLS
0001:0002:0002:0080:<HTML>
0005:0002:0002:8080:<BR>
0005:0012:0002:8080:<BR>
0001:0002:0002:0080:<BODY>
0005:0002:0002:8080:<B>HELLO</B><BR>
0002:0004:0002:0090:100000000000000000022
0001:0002:0003:0021:DEL
0002:0004:0002:0010:100000000000000000023
Each colon from the file shows what part of the packet structure it should be a part of, i.e. the first set of 4 numbers is the "source" then "destination and so forth.
One way to do this is :
Use fgets to read the file line by line.
For each line, use strtok to tokenize the string.
For each of the first four tokens, use strtol to convert it to an integer.
A. The line char *fgets(DataLine, 70, (FILE) *DataFile); should probably just read fgets(DataLine, 70, DataFile);
B. If you create a single variable you don't really need malloc since the compiler will allocate it, but if you are planning on creating an array of Data you will only need to call malloc once to create the whole array, something like:
struct packet* packetarr = malloc(sizeof packetarr * DESIRED_ARRAY_SIZE);
C. As downHillFromHere suggested, use strtok to get each part of the string and strtol to convert the read strings to numbers when appropriate.
Related
So I've written a program that will take in a information about a dvd (specifically it's postion, IDkey(just some random number) Title, Genre and Year of release), and using a struct it will write that info to a .txt file called "person.txt". I'm positive my code works for the most part but when I go to test it the output received in the .txt file is written in some weird symbol language and not English and quite frankly I have no idea as to why this is. Any explanation on why this is happening would be much appreciated, thanks :)
PROGRAM
#include <stdio.h>
#include <stdlib.h>
// a struct to read and write
struct dvd
{
int fposition;
int fIdKey;
char ftitle[50];
char fgenre[50];
int fyear;
};
int main ()
{
FILE *outfile;
struct dvd input;
// open file for writing
outfile = fopen ("person.txt", "w");
if (outfile == NULL)
{
fprintf(stderr, "\nError opend file\n");
exit (1);
}
printf("Postion: ");
scanf("%d", &input.fposition);
printf("ID Key: ");
scanf("%d", &input.fIdKey);
printf("Title: ");
scanf("%s",&input.ftitle);
printf("Genre: ");
scanf("%s", &input.fgenre);
printf("Year: ");
scanf("%d", &input.fyear);
// write struct to file
fwrite (&input, sizeof(struct dvd), 1, outfile);
if(fwrite != 0)
printf("contents to file written successfully !\n");
else
printf("error writing file !\n");
// close file
fclose (outfile);
return 0;
}
TEST RUN
TEST RUN OUTPUT IN THE .TXT FILE
You are writing these values to the file:
int fposition;
int fIdKey;
char ftitle[50];
char fgenre[50];
int fyear;
But you are displaying the whole file as characters. That kind of works for ftitle and fgenre because they really are characters...though since you don't populate all 50 characters there are some ugly uninitialized characters shown as well. That is easy to fix: just fill the unused characters (as well as the null terminator) with some known character (such as space) before writing to the file, or do not write the unused characters at all. You can use strlen() to find the length of each string and memset() to set the unused characters to a well-known character which is printable.
Next, saving an int and reading it as text is problematic. You need to decide on a single format. Either you write as integers like now, and you read as integers (which means you need a special program to read the file), or you commit to writing only text to the file.
Easiest might be to only write text to the file. You can use fprintf() for that, instead of fwrite(). You can use fprintf() for the character arrays as well, it will automatically write only the "used" part of each string up to the null terminator, skipping all the "garbage" characters.
Below is my code, I have been working on this part for some structure am create a C socket server that can process data for clients, but I got a problem in file handling. I wanted to pick data from a file and store it into a structure at specific portions and then I erase the file according to data I have picked.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "struct.h"
struct student {
char command[10];
char value[50];
char user[50];
};
int main() {
int size, i;
struct student s1[256];
FILE *file = fopen("file.txt", "r");
if (file == NULL) {
printf("Error in reading student data");
return 1;
}
size = 0;
while(fscanf(file,"%s,%s,%s",
s1[size].command,
s1[size].value,
s1[size].user) != EOF) {
printf("%s%s%s\n",s1[size].command,s1[size].value,s1[size].user);
printf("%s\n",s1[size].command);
size++;
}
fclose(file);
return 0;
}
I wanted to pick data from my file which contains the below information and I store it in specific portions of my structure array
a,w,a
r,e,1
i.e. if I store
a in s1[0].command
w in s1[0].value
a in s1[0].user
and
r in s1[1].command
e in s1[1].value
1 in s1[1].user
But when I try running my code it prints
a, w, a in s1[0].command
and
r, e, 1 in s1[1].command
so I am kindly requesting for help because I have tried googling but I couldn't get a solution.
The "%s" format reads space-separated "words".
If there isn't a space separating the "words" you have to use some other way to parse the input. For example by reading the whole line and then use something like strtok to "tokenize" the string.
Or make sure that the input format is space-separated.
I have seen programs for file handling and in one of the program using fseek as shown below:
/* This example opens a file myfile.dat for reading.
After performing input operations (not shown), it moves the file
pointer to the beginning of the file.
*/
#include <stdio.h>
int main(void)
{
FILE *stream;
int result;
if (stream = fopen("myfile.dat", "r"))
{ /* successful */
if (fseek(stream, 0L, SEEK_SET)); /* moves pointer to */
/* the beginning of the file */
{ /* if not equal to 0
then error ... */
}
else {
/* fseek() successful */
}
}
Like this can one move the file pointer to the next line immediately after that line
BO_ 377 FC_DM_MISC: 8 FC
SG_ DATA3 m11 : 31|8#0+ (1,0) [0|0] "" DM
These are the two lines and I want to program in a way that when one identifies the number 377 the pointer should now go to the next line i.e., to the line SG_ DATA3 inspite of the white spaces after 8 FC. How can one do that using fseek in C?
Try this code . It may help you .Here the Each line of the Input file is converted to string ,since string manipulation is very simple comparing to complex fseek() function.This may not be perfect answer but this will be very simple solution.
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *stream;
int result;
char tmp[100]; // assuming that max length of a line in myfile.dat is 100.
if (stream = fopen("myfile.dat", "r"))
{ /* successful */
fscanf(stream, "%100[^\n]", tmp); // assuming that max length of a line in myfile.dat is 100.
printf("%s", tmp);
if (strstr(tmp, "377"))
{ // check for 337
fscanf(stream, "%100[^\n]", tmp); // next line is in the string tmp .
// continue your program.
//printf("%s", tmp);
}
}
}
fseek is used for binary data, if you work on a text file you should use either fgets or getline(recommended to use getline).
There's an open discussion of "fgets() vs getline" and many say that "fgets is deprecated" is only a gcc propaganda in favor to their specific getline().
A possible flaw in fgets() is that it doesn't tell you anything if there are null bytes being read, something you can get away with getline().
But then again if you don't like gcc, or use something different, use fgets(). If you are stuck with gcc, then use getline().
I need to read a text file with 7 lines into 7 different variables. The text file looks like this:
.2661
A.txt
B.txt
C.txt
1
2
0.5 0.6
These are the variables that I need to store each line into:
float value1; // line 1 from .txt file
char *AFileName; // line 2 from .txt file
char *BFileName; // line 3 from .txt file
char *CFileName; // line 4 from .txt file
int value2; // line 5 from .txt file
int lastLineLength; // line 6 from .txt file
double lastLine[lastLineLength]; // line 7 from .txt file - this can be different lengths
I have currently been doing this by just using the arguments when I call my program from the command line and the argv command.
First open the file using fopen with read access:
FILE *inputFile = fopen(filename, "r");
if(!inputFile) {
// Error opening file, handle it appropriately.
}
Then read the data from the file using fscanf. The first parameter is the FILE * we created above. The second parameter is a format string that specifies what fscanf should expect while reading the file. The remaining parameters are pointers to variables that will hold the data read from the file.
int variablesFound;
variablesFound = fscanf(inputFile, "%f\n%s\n%s\n%s\n%d\n%d\n", &value1, AFileName, BFileName, CFileName, &value2, &lastLineLength);
if(variablesFound < 6) {
// There was an error matching the file contents with the expected pattern, handle appropriately.
}
double lastLine[lastLineLength];
// Iterate over the last line.
int lastLineIndex;
for(lastLineIndex = 0; lastLineIndex < lastLineLength; lastLineIndex++) {
fscanf(inputFile, "%lf", &lastLine[lastLineIndex]);
fscanf(inputFile, " "); // Eat the space after the double.
}
Edit
After comments I realized it might be worth noting that you have to allocate memory to your variables as the real first step. The primitives (those with an & below) can be declared as normal. For the string (char array), you'll want to do one of the following:
char *aFileName = calloc(MAX_FILENAME_SIZE + 1, sizeof(char));
or
char aFileName[MAX_FILENAME_SIZE + 1];
Depending on what your purpose with aFileName would be determines which method would be appropriate. However, assuming this code appears in the main or doesn't need to exist beyond the scope of the function, the latter would be better as it doesn't require free()ing the variable after you're done with it.
It also may be worth while singling out the code that deals with reading input if your requirements change often.
You can read from the file as follows:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE * fp;
char * line = NULL;
size_t len = 80;
fp = fopen("<path to your file>", "r");
if (fp == NULL)
exit(-1);
while (getline(&line, &len, fp) != -1)
printf("%s", line);
fclose(fp);
return 0;
}
getline reads character strings from the file, so you'd have to parse the lines as needed (atoi, atof).
I am using Code::Blocks and have set the command-line arugments via the IDE. I have also opened the executable with the proper argument and I can't manage to get a non-NULL on fopen() return. I've tried hard-coding the filename also with no success. The platform is Windows XP SP3.
The first is the one that fails, when i hardcoded it i used double backlash. Also i never knew if the second works because i never managed to start the process by opening the first one.
Obviously i put the text file in the same directory that the executable and rebuilt the executable many times, but it still doesn't work.
EDIT: I added the perror("fopen"); line in the if(finput==NULL) block. This is the output.
http://prntscr.com/h71pa
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define first_part_url "[url=http://magiccards.info/query?q="
#define second_part_url "&v=card&s=cname]"
#define end_bracket "[/url]\n"
#define output_file_prefix "output_"
char* get_card(FILE* finput);
int main(int n, char* arguments[])
{
FILE* finput;
FILE* foutput;
short int counter;
char* output_filename;
char* finalstring;
for(counter=1; counter<n; counter++)
{
finput=fopen(arguments[counter], "r");
if (finput==NULL)
{
printf("Unable to open ");
puts(arguments[counter]);
perror("fopen");
break;
}
strcpy(output_filename, output_file_prefix);
strcat(output_filename, arguments[counter]);
if((foutput=fopen(output_filename, "w"))==NULL)
{
printf("There was an error while trying to open ");
puts(arguments[counter]);
printf(" .\n");
break;
}
while(!feof(finput))
{
finalstring=get_card(finput);
fputs(finalstring, foutput);
while(((fgetc(finput))!='\n')||feof(finput));
}
printf("Autocarding ");
puts(arguments[counter]);
printf(" was a success.\n");
fclose(foutput);
}
if(finput!=NULL)
{
fclose(finput);
free(finalstring);
}
return 0;
}
char* get_card(FILE* finput)
{
char* currentcard;
char* finalstring;
currentcard=(char*)malloc(sizeof(char)*150);
fgets(currentcard, 150, finput);
/* Allocates the exact amount of space needed for the final string*/
finalstring=(char*)malloc(sizeof(char)*(strlen(first_part_url)+strlen(second_part_url)+strlen(end_bracket)+strlen(currentcard)));
/* Get all the final forum link together*/
strcat(finalstring, first_part_url);
strcat(finalstring, currentcard);
strcat(finalstring, second_part_url);
strcat(finalstring, end_bracket);
free(currentcard);
return finalstring;
}
The error you are getting, "No such file or directory" indicates that the file name you're trying to open doesn't exist.
In this case, it's probably because the program's current working directory is not the same as the directory containing the executable file.
This
finput=fopen(arguments[counter], "r");
Will only fail if you do not supply correct filenames (e.g. if there are non-ASCII characters in the names or the names do not include the correct path, fopen() opens files in the current directory if no path is specified in the file name).
This
output_filename=(char*)malloc(sizeof(arguments[counter]));
most likely does not allocate enough space for a name because arguments[counter] is a pointer, and sizeof() of a pointer is not the same as strlen(that_same_pointer) + 1.
This
output_filename=output_file_prefix;
loses the just allocated memory because you are reassigning the pointer output_filename to point to some other place, output_file_prefix ("output_").
After the above this
strcat(output_filename, arguments[counter]);
is likely going to crash your program because this is going to attempt to overwrite a string literal ("output_"), doing which causes undefined behavior per the C standard.
You have to allocate enough cumulative space for the strings that you want to concatenate and you have to concatenate them in the allocated space.
To save you even more trouble, here's another problem:
finput=fopen(arguments[counter], "r");
...
while(!feof(finput))
feof() only works after at least one read from a file. This has been asked ans answered multiple times.
Try changing
for(counter=1; counter<n; ++n)
{
to
for(counter=1; counter<n; ++counter)
It appears the code loops infinitely, therefore it would exhaust the possible elements in your argument array causing a NULL pointer to be returned.