Related
I have 3 CSV files. The first of them contains 4 columns:
ID,Section1,Section2,Secion3
1,23,12,7
2,11,26,9
. . . .
. . . .
19,30,22,4
20,5,6,16
The first column is the ID and the other three contain random numbers ranging from 0 to 30.
The next file is a "conversion" file. It shows the corresponding value to each number:
30,45,44,45
29,44,42,43
28,43,42,41
. . . .
. . . .
1,22,21,22
0,20,21,21
The first column is the number to be read and the next columns are the values that will replace those numbers in each Section.
Like, if you read a 30 in Section1 it will be replaced by a 45, and if you find a 29 in Section 2 it will be replaced by a 42 and so on.
If I were to write the converted numbers into a third CSV file with the same 4 column format, how should I do it?
So far I've had no problems with generating the files since they are randomized, except for the "conversion" file, but I don't know how to proceed with the conversion.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int main (int argc,char *argv[]){
int i, num1;
char numbers[20][20];
char conversions[20][20];
//File with the initial numbers
FILE *registry = fopen("registry.csv","w+");
if (registry == NULL){
fputs ("File error",stderr);
exit (1);
}
//Conversion file
FILE *conversion = fopen("conversion.csv","r");
if (conversion == NULL){
fputs ("File error",stderr);
exit (1);
}
//File where the resulting values will be written
FILE *results = fopen("results.csv","a");
if (results == NULL){
fputs ("File error",stderr);
exit (1);
}
//Writing the headers
fprintf(results,"ID,Results1,Results2,Results3\n");
fprintf(registry,"ID,Section1,Section2,Section3\n");
srand(time(0));
//Generating the random numbers
for(i=1;i<21;i++){
sprintf(numbers[i],"%d,%d,%d,%d\n",i,rand()%31,rand()%31,
rand()%31);
fputs(numbers[i], registry);
}
//This is where I don't know how to proceed
for(i=1;i<21;i++){
sprintf(conversions[i],"%d,%d,%d,%d\n",i,
fscanf(registry,"%d,%*s,%*s,%*s\n",num1)...);
}
I was trying to do something like what I did to generate the random numbers by saving everything into a buffer and then writing it into the file and I found that the fscanf function can be of great use to skip the parts I don't need to read, but I couldn't figure out how to use it to skip the headers and the ID column and I'm still missing the conversion part.
Conversion file:
30,45,44,45
29,44,43,43
28,43,42,42
27,43,41,40
26,41,40,40
25,40,39,39
24,39,37,39
23,38,37,38
22,38,36,37
21,36,36,37
20,35,35,36
19,34,34,35
18,33,34,35
17,33,33,34
16,32,32,33
15,32,31,32
14,31,30,31
13,30,30,31
12,29,29,30
11,29,28,29
10,28,28,29
9,28,27,27
8,27,26,26
7,27,26,25
6,26,25,25
5,25,24,24
4,25,23,24
3,24,23,23
2,23,22,21
1,21,21,20
0,20,21,20
This answer is scoped to address:
//This is where I don't know how to proceed.
To do what you have described, if it is not necessary to include the first columns in registry, results or conversion for storing, then do not. Although nice for human readability, they complicate the task of reading in, and using arrays. The unused column data and header row requires array indexing gymnastics to get the data to line up correctly into the arrays.
Without the header row and numbering column, array indexes alone are sufficient to track all that is needed to make the conversion.
However, if you feel the first column/row is needed for your purposes, then adjust the array indexing of the routines shown below to accommodate.
The following steps (some of which you already do) are what I identified as essential toward making the conversion step as simple as possible...
Steps:
Create registry - 60 - random numbers (0-30) arranged in 20 rows, 3
data columns
Create int reg[20][3] = {{0}};
Read registry into reg array using a combination fgets sscanf routine.
Example:(assuming registry has already been created in your code)
registry = fopen(".\\registry.csv","r");
if (registry)
{
while(fgets(buf, sizeof(buf), registry))
{
sscanf(buf, "%d,%d,%d", ®[index][0],®[index][1],®[index][2] );
index++;
}
fclose(registry);
}
conversion table - pre-existing file
Create int conv[31][3] = {{0}};
Read conversion table into conv array using a combination fgets sscanf routine (see above example)
Once you have these arrays created properly,
Perform conversion:
Create int res[20][3] = {{0}};
Create char buf[80] = {0};
Open 'results' file: FILE *results = fopen(".\\results.csv","w");
populate results:
Example:
//File where the resulting values will be written
FILE *results = fopen(".\\results.csv","w");
if (results)
{
for(i=0;i<sizeof(reg)/sizeof(reg[0]);i++)
{
for(j=0;j<sizeof(reg[0])/sizeof(reg[0][0]);j++)
{
res[i][j] = conv[reg[i][j]][j];
// | | |___reg col == conv col
// | |______value reg == conv row
// |________________________________row and column of conv
}
sprintf(buf, "%d,%d,%d\n", res[i][0],res[i][1],res[i][2]);
fputs(buf, results);
}
fclose(results);
}
At this point, you can print the results file in a format that suits your needs.
Following is an image showing actual results using suggested approaches above for a randomly generated registry, the values you provided for conversion and resulting results. (each created without column 1 shown in your original code, as I suggested in my comments.) Image is showing indexing from 0 - n for each set of array data:
I want to read data from a text file and store the data.
I can not all the data using getc() as it will take all the data at once, and I do not know how to distribute that for my use.
Data is in form of:
John
Sebastian
1
2 //Number of notes(So, when I read this value and run a loop to collect all
notes)
12 //note 1
21 //note 2
#include <stdio.h>
struct StudentDetails
{
char firstName[100], secondName[100];
int notes[100][30], id;
struct StudentDetails *next;
};
int main()
{
FILE *input;
input = fopen("input.txt", "r");
if (!input)
{
while (input != EOF)
{
//what to do to store in different variable rather in one.
}
}
else
{
printf("File not found");
}
}
Please try fread() function for reading a record from a file and fwrite(), it's used to write a record to the file.
eg: fwrite(&sd,sizeof(sd),1,input);
for student record no need of struct StudentDetails *next; (we are not doing anything like linked list, we just write different student record in a file. So you just define structure variable as StudentDetails SD in main that is more than enough each iteration of loop you can write one student record to file.)
for reading you can use
while(fread(&sd,sizeof(sd),1,input) > 0 )
{
printf("Name:%s",sd.name);//this you can do ...
}
I hope it will help you :)
I am reading data from a number of files, each containing a list of words. I am trying to display the number of words in each file, but I am running into issues. For example, when I run my code, I receive the output as shown below.
Almost every amount is correctly displayed with the exception of two files, each containing word counts in the thousands. Every other file only has three digits worth of words, and they seem just fine.
I can only guess what this problem could be (not enough space allocated somewhere?) and I do not know how to solve it. I apologize if this is all poorly worded. My brain is fried and I am struggling. Any help would be appreciated.
I've tried to keep my example code as brief as possible. I've cut out a lot of error checking and other tasks related to the full program. I've also added comments where I can. Thanks.
StopWords.c
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <stddef.h>
#include <string.h>
typedef struct
{
char stopwords[2000][60];
int wordcount;
} LangData;
typedef struct
{
int languageCount;
LangData languages[];
} AllData;
main(int argc, char **argv)
{
//Initialize data structures and open path directory
int langCount = 0;
DIR *d;
struct dirent *ep;
d = opendir(argv[1]);
//Count the number of language files in the directory
while(readdir(d))
langCount++;
//Account for "." and ".." in directory
//langCount = langCount - 2 THIS MAKES SENSE RIGHT?
langCount = langCount + 1; //The program crashes if I don't do this, which doesn't make sense to me.
//Allocate space in AllData for languageCount
AllData *data = malloc(sizeof(AllData) + sizeof(LangData)*langCount); //Unsure? Seems to work.
//Reset the directory in preparation for reading data
rewinddir(d);
//Copy all words into respective arrays.
char word[60];
int i = 0;
int k = 0;
int j = 0;
while((ep = readdir(d)) != NULL) //Probably could've used for loops to make this cleaner. Oh well.
{
if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
{
//Filtering "." and ".."
}
else
{
FILE *entry;
//Get string for path (i should make this a function)
char fullpath[100];
strcpy(fullpath, path);
strcat(fullpath, "\\");
strcat(fullpath, ep->d_name);
entry = fopen(fullpath, "r");
//Read all words from file
while(fgets(word, 60, entry) != NULL)
{
j = 0;
//Store each word one character at a time (better way?)
while(word[j] != '\0') //Check for end of word
{
data->languages[i].stopwords[k][j] = word[j];
j++; //Move onto next character
}
k++; //Move onto next word
data->languages[i].wordcount++;
}
//Display number of words in file
printf("%d\n", data->languages[i].wordcount);
i++; Increment index in preparation for next language file.
fclose(entry);
}
}
}
Output
256 //czech.txt: Correct
101 //danish.txt: Correct
101 //dutch.txt: Correct
547 //english.txt: Correct
1835363006 //finnish.txt: Should be 1337. Of course it's 1337.
436 //french.txt: Correct
576 //german.txt: Correct
737 //hungarian.txt: Correct
683853 //icelandic.txt: Should be 1000.
399 //italian.txt: Correct
172 //norwegian.txt: Correct
269 //polish.txt: Correct
437 //portugese.txt: Correct
282 //romanian.txt: Correct
472 //spanish.txt: Correct
386 //swedish.txt: Correct
209 //turkish.txt: Correct
Do the files have more than 2000 words? You have only allocated space for 2000 words so once your program tries to copy over word 2001 it will be doing it outside of the memory allocated for that array, possibly into the space allocated for "wordcount".
Also I want to point out that fgets returns a string to the end of the line or at most n characters (60 in your case), whichever comes first. This will work find if there is only one word per line in the files you are reading from, otherwise will have to locate spaces within the string and count words from there.
If you are simply trying to get a word count, then there is no need to store all the words in an array in the first place. Assuming one word per line, the following should work just as well:
char word[60];
while(fgets(word, 60, entry) != NULL)
{
data->languages[i].wordcount++;
}
fgets reference- http://www.cplusplus.com/reference/cstdio/
Update
I took another look and you might want to try allocating data as follows:
typedef struct
{
char stopwords[2000][60];
int wordcount;
} LangData;
typedef struct
{
int languageCount;
LangData *languages;
} AllData;
AllData *data = malloc(sizeof(AllData));
data->languages = malloc(sizeof(LangData)*langCount);
This way memory is being specifically allocated for the languages array.
I agree that langCount = langCount - 2 makes sense. What error are you getting?
I am making a quiz program in c for a school project.I was storing question and answers in a text file.The text file contains 1 question and followed by 4 choices and a correct answer(each in a new line) and so on.The code for file handling is
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<process.h>
void main()
{
int tnum=2,mnum;
printf("Enter a file name to load the quiz from or enter dhruv.txt to load the default file\n");
printf("(For type of file and arrangement of data in it, refer to the documentation\n");
printf("WARNING: An improper quiz file may result in malfunctioning of the program.\n");
char quizfile[100];
scanf("%s",quizfile);
FILE *dj;
dj = fopen(quizfile,"r");
int test = 1;
while(dj == NULL)
{
printf("Requested file does not exist.Please enter a valid name\n");
scanf("%s",quizfile);
dj = fopen(quizfile,"r");
test++;
if(test == 5)
{
exit(0);
}
}
char line[500];
char ques[20][500],ansa[20][500],ansb[20][500],ansc[20][500],ansd[20][500],anse[20][500];
int start = 1,quesval=1,ans1=1,ans2=1,ans3=1,ans4=1,ans5=1;
while(fgets(line,sizeof line,dj) != NULL)
{
if((start%6) == 1)
{
strcpy(ques[quesval],line);
quesval++;
}
if((start%6) == 2)
{
strcpy(ansa[ans1],line);
ans1++;
}
if((start%6) == 3)
{
strcpy(ansb[ans2],line);
ans2++;
}
if((start%6) == 4)
{
strcpy(ansc[ans3],line);
ans3++;
}
if((start%6) == 0)
{
strcpy(anse[ans5],line);
ans5++;
}
if((start%6) == 5)
{
strcpy(ansd[ans4],line);
ans4++;
}
start++;
}
fclose(dj);
printf("Quiz file successfully loaded\n");
printf("/t/t WELCOME TO THE QUIZ\n\n");
printf("Every team must select one of the four correct answers to the asked questions to gain points\n");
printf("Wrong answer will not be penalized\n");
for(int k =1;k<quesval;k++)
{
int myvar;
myvar = k%tnum;
if(myvar == 0)
{
myvar = tnum;
}
printf("Question for TEAM %d\n\n",myvar);
printf("%s \n A.%s B.%s C.%s D.%s\n",ques[k],ansa[k],ansb[k],ansc[k],ansd[k]);
}
getch();
}
The problem is
if((start%6) == 0)
{
strcpy(anse[ans5],line);
ans5++;
}
The program shows File does not exist if i use this but as soon as i comment it out the program works fine.I don't know what the error is.Please do help
EDIT:My text file looks like:
Who is the owner
dhruv
jain
kalio
polika
dhruv
who is his friend
sarika
katrina
jen
aarushi
aarushi
where is he
home
office
college
toilet
office
where will he go
home
office
college
toilet
home
EDIT
I am using Turbo c++ in windows 7 using DOSBOX..The script is updated above
It's difficult to say without seeing your input file, but I suspect that your array declarations are backwards. For example, you have:
char ques[500][20];
This declares an array of 500 elements, where each element can be up to 20 characters. You probably want:
char ques[20][500];
This declares an array of 20 elements, where each element can be up to 500 characters.
If your input file contains lines longer than 20 characters, then your current code is likely overwriting your arrays.
There are several problems here but your immediate problem is this:
strcpy(anse[ans5],line);
(And all the other strcpy calls like it.)
You are copying line to the array beginning at anse[1][0]. If line contains more than 20 characters, it will overwrite memory past the end of anse. For example, if line contains 25 characters, you'll be putting it in anse[1][0] through anse[1][24]. Unfortunately anse[1][24] does not exist because anse is only 20 characters long. If any question exceeds 20 characters, you'll be corrupting memory and possibly causing a crash. Let me guess: Question 5 is longer than 19 characters, right?
In short, you have your rows and columns mixed up in your declarations. I think you wanted to allow 20 questions of 500 characters each, but you're actually allowing 500 questions of 20 characters each.
Next problem: In C, arrays are zero-based, not one-based. The first string in ques, for example, is ques[0], not ques[1].
To simplify this, think of two-dimensional arrays as a table composed of rows and columns. For example, declare a 3x4 array named foo:
char foo[3][4];
Picture it like this:
0 1 2 3
0 . . . .
1 . . . .
2 . . . .
What I have is an array of three character strings, each 4 characters long. The first string in my array is at foo[0]. The first character of the first string is at foo[0][0]. The second character is at foo[0][1], the second character of the third string is foo[2][1], and so on.
To solve this, your declarations should look like this:
char ques[20][500],ansa[20][500],ansb[20][500],ansc[20][500],ansd[20][500],anse[20][500];
int start = 1,quesval=0,ans1=0,ans2=0,ans3=0,ans4=0,ans5=0;
When you get it working, you should then ask yourself why you're testing the value of start six times each pass through the loop when it only changes once. There's a much better solution available here. Consider a three-dimensional array like this:
char answers[20][500][5];
That gives you 20 questions with 5 answers each.
I have a file car.txt and a file reservation.txt. Both the files have a reservation number (Rxxx).
I want to use the reservation number from reservation.txt to print the details of the car with the corresponding reservation number. Or more accurately, I'm trying to find the details of all the cars that are available at any given date.
car.txt:
(from let to right: reservationID, carID, carYOM, carMake, carModel, carFuel, catagory)
R002;V001;2003;Toyota;Camry;Petrol;Budget
R007;V002;2005;Toyota;Prius;Petrol;Economy
R001;V003;1999;Ford;Falcon;Petrol;Midsize
R008;V004;2007;Ford;Territory;Diesel;Fullsize
R011;V005;2010;Ferrari;599;Petrol;Fullsize
R035;V006;1998;Holden;Comadore;Diesel;Midsize
R006;V007;2008;Honda;Civic;Petrol;Budget
R004;V008;2000;Mazda;MX5;Petrol;Economy
reservation.txt:
(from let to right: reservationID, customerID, reservationStartDate, reservationStartTime, reservationEndDate, reservationEndTime)
R001;C005;12/02/2012;09:15A.M;15/03/2012;05:00P.M
R002;C002;15/04/2012;10:00A.M;22/04/2012;10:30A.M
R003;C003;16/01/2012;02:11P.M;15/04/2012;12:00P.M
R004;C004;05/05/2012;03:00P.M;08/05/2012;10:40A.M
R005;C005;15/04/2012;10:00A.M;23/04/2012;05:00P.M
R006;C006;11/04/2012;05:30P.M;15/04/2012;10:00A.M
R010;C008;15/05/2012;03:15P.M;18/05/2012;11:00A.M
R011;C007;15/04/2012;11:40P.A;23/04/2012;09:00A.M
If I enter any date It only gets up to the point where it decides if the entered date is between the reservation start and end date. "all the cars are available".
However, if I enter 13/02/2012, It prints "no matching resID in cars.txt" 7 times.
The code in question:
#include <stdio.h>
#include <string.h>
#define MAX_CAR 100
#define MAX_RES 100
int main(){
typedef struct{ //car struct
char reservationID[20];
char carID[20];
char carYOM[20];
char carMake[20];
char carModel[50];
char carFuel[20];
char catagory[20];
} car_t;
typedef struct{ //res struct
char reservationID[20];
char customerID[20];
char reservationStartDate[20];
char reservationStartTime[20];
char reservationEndDate[50];
char reservationEndTime[20];
} res_t;
car_t car[MAX_CAR]; //car array
res_t reservation[MAX_RES]; //res array
FILE *carHandle;
FILE *resHandle;
char line[100];
char *item;
int rescount = 0;
int carcount =0;
int k;
int i;
int option;
char choice[20];
resHandle = fopen("reservation.txt","r");
while (fgets(line, 99, resHandle)){ //cut up the reservation file line by line and put the bits into the res array.
item = strtok(line,";");
strcpy(reservation[rescount].reservationID,item);
item = strtok(NULL,";");
strcpy(reservation[rescount].customerID,item);
item = strtok(NULL,";");
strcpy(reservation[rescount].reservationStartDate,item);
item = strtok(NULL,";");
strcpy(reservation[rescount].reservationStartTime,item);
item = strtok(NULL,";");
strcpy(reservation[rescount].reservationEndDate,item);
item = strtok(NULL,"\n");
strcpy(reservation[rescount].reservationEndTime,item);
rescount++;
}
fclose(resHandle);
carHandle = fopen("car.txt","r");
while (fgets(line, 99, carHandle)){ //cut up the car file line by line and put the bits into the car array.
item = strtok(line,";");
strcpy(car[carcount].reservationID,item);
item = strtok(NULL,";");
strcpy(car[carcount].carID,item);
item = strtok(NULL,";");
strcpy(car[carcount].carYOM,item);
item = strtok(NULL,";");
strcpy(car[carcount].carMake,item);
item = strtok(NULL,";");
strcpy(car[carcount].carModel,item);
item = strtok(NULL,";");
strcpy(car[carcount].carFuel,item);
item = strtok(NULL,"\n");
strcpy(car[carcount].catagory,item);
carcount++;
}
fclose(carHandle);
printf("Enter todays date:");
scanf("%s", choice);
for (k=0;k<=rescount; k++){
if (strcmp(choice,reservation[k].reservationEndDate)<0 && strcmp(choice,reservation[k].reservationStartDate)>0){
for (i=0;i<=carcount; i++){
if (strcmp(car[k].reservationID,reservation[i].reservationID)==0){
printf("\nreservationID: %s\nreservationStartTime: %s\ncustomerID: %s\ncarid: %s\nyom: %s\nmake: %s\nmodel: %s\nfueltype: %s\ncategory: %s\n\n", car[k].reservationID, reservation[i].reservationStartTime, reservation[i].customerID, car[k].carID, car[k].carYOM, car[k].carMake, car[k].carModel, car[k].carFuel, car[k].catagory);
//printf("This works");
goto outofloop;
}else printf("\n\nno matching resID in cars.txt\n");
}
}
else printf("\nall the cars are available\n");
break;
}
outofloop:
return(0);
}
Any help would be appreciated. :)
EDIT: Updated code.
This is the output, still wrong :(:
Enter todays date:13/02/2012
no matching resID in cars.txt
reservationID: R002
reservationStartTime: 10:00A.M
customerID: C002
carid: V001
yom: 2003
make: Toyota
model: Camry
fueltype: Petrol
category: Budget
Press any key to continue . . .
Enter todays date:13/02/2012
all the cars are available
Press any key to continue...
You're not counting the number of cars and reservations correctly:
In both loops (the one that reads cars, and the one that reads reservations), you're using reccount as the counter.
You need to use two counters, carcount and rescount.
Later on, then, you need to use carcount and rescount in your for loops.
for (k=0;k<=rescount; k++){
if (strcmp(choice,reservation[k].reservationEndDate)<0 && strcmp(choice,reservation[k].reservationStartDate)>0){
for (i=0;i<=carcount; i++){
You should also consider dynamically allocating memory for the car and reservation arrays, as well as for the character arrays inside car_t and reservation_t, since your current code will (even when the obvious bug is fixed) segfault or give unexpected results as soon as your input files have over MAX_CAR/MAX_RES lines, or the strings in the lines are too long.
Update
There are still several issues with your updated code:
You should not store data that's not supposed to be a string in a string variable. Store as much as possible in integer or unsigned variables, especially IDs and dates.
Speaking about dates: Simply use time(NULL) to get the current time in UNIX time format ("seconds from 1970-01-01 00:00"). Store all dates as an integer in UNIX time.
When reading the file, check if carcount is greater than CAR_MAX
for(carcount = 0; carcount < CAR_MAX; carcount++)
You should use fscanf when reading the textfile:
if(fscanf(filehandle, "R%03u...\n", &car[carcount].reservationID, ...) == EOF)
break;
This will make your file scanning much more robust and turn it into a one-liner.
Avoid string comparisions wherever possible. Instead, use 'real datatypes'.
Avoid gotos, really. It is true that Linux kernel developers use them, but they know what they're doing.
Your outer for loop contains a break statement that will, in every case, break the loop execution after the first run. You probably forgot braces after 'else'.
I think your program flow logic contains some errors. You printf("\n\nno matching resID in cars.txt\n") after every single car.
In general, have you tried debugging your code? gdb is a really powerful utility. You can use it to follow the program flow, pause your program at look at variable contents at any time.
I have fixed the issue. The problem was using resID as a common identifier instead of carID.
Thanks for the help everyone.