How to read date from file into structure? - c

I had really hard time in finding solution mostly because popular searchers think that data and date are the same, by date i mean e.g 11/10/2014 9:00.
Alright so i have a structure
struct Rezervations{
char user_login[10];
int room_number;
char date[40];
} rezervations[100];
i have file "reservations.txt" where I'm holding my data's like this:
LOGIN1;5;11/10/14 09:00:00; LOGIN2;1;12/10/14 09:00:00;
etc
To this point i was reading this kind of files using if like this
int loadReservation()
{
char reserved[200];
char temNumber[2];
fp=fopen("rezervations.txt", "r");
fscanf(fp, "%s", reserved);
int i;
int z=0;
int k=0;
char temp[10];
for(i=0;i<strlen(reserved);i++)
{
int j=0;
while(reserved[i]!=59)
{
temp[j]=reserved[i];
j++;
i++;
}
if (z==0||z%3==0)
{
memcpy(reservations[k].user_login,temp,j);
}
else if (z==1||z%3==1)
{
memcpy(tempLiczba,temp,j);
reservations[k].room_number = tempLiczba[0] - '0';
}
else if (z==2||z%3==2)
{
memcpy(reservations[k].date,temp,j);
k++;
}
z++;
}
fclose(fp);
return k;
}
I know this code is messy but I hope u will see what I'm trying to accomplish here. I haven't used malloc yet (with reserved e.g) but thats no my question, I'd like to know how to read this date.
but unfortunately for me with date it stopped working. My guess it stopped working because my date contains / and : but I have no idea how to bypass it. This date is generated by strftime() and I would like not to change it.
Also if you can look at rezervations[k].room_number = tempLiczba[0] - '0'; because that's how I'm reading integer from text file.

Well, there's probably a hundred ways to achieve this in C, but one (easy one) might be to use one of the variants of sscanf.
http://www.tutorialspoint.com/c_standard_library/c_function_sscanf.htm
Example/pseudocode
char * line_from_file = read_next_line();
sscanf(line_from_file, "%s;%d;%s", rezervations[k].user_login, &rezervations[k].room_number, rezervations[k].date);
Edit:
Maybe %s only stops reading on whitespace, and as yours is semicolon seperated, you may need something like
sscanf(line_from_file, "%[^;];%d;%[^;]", ...)

Related

Frequency of each word of text file. Error while allocating memory?

Good evening everyone!
I have started messing around with strings and pointers in C.
I want to write a programm that reads a text file, then calculating the frequency of each word and printing it.
My variables are:
FILE *fp;
char *words[N] //N defined 100
int i=0, y=0;
int *freq;
int freq_count=0;;
int word_number=0;
The code part:
for(i=0;i<word_counter;i++){
while(y<word_counter){
if(strcmp(words[i],words[y]==0){
freq1++;
} y++;
}
if(i==0){
freq=(int*)malloc(sizeof(int));
strcpy(freq, freq1); freq1=0;
}
else{
freq=(int*)realloc(freq, (i+1)*sizeof(int));
strcpy(freq, freq1); freq1=0;
}
y=0;
}
I get several errors running this...What is wrong?
Take into consideration that in words[N] i have put each word of the text by itself in each cell.
Thank you all in advance.
Maybe another array is not what you want, but still better than using realloc and condition in loop.
int freq[N];
for(i=0;i<word_counter;i++){
freq1 = 0;
for(y=0;y<word_counter;y++){
if(strcmp(words[i],words[y]==0)
freq1++;
}
freq[i] = freq1;
}

C Transforming array into string using sprintf

I have scanned "ABCDEFGHIJK" with fscanf into a char array[26]. Then I got "ABCDEFGHIJK" using "for" into another array[11]. Now I need to get to an "ABCDEFGHIJK.mp4" array[15] in order to feed that filename into a rename function.
I don't know much about C programming besides printf, scanf, for and while.
sprintf(filename, "%c%c%c%c%c%c%c%c%c%c%c.mp4", codigo[0], codigo[1], codigo[2], codigo[3], codigo[4], codigo[5], codigo[6], codigo[7], codigo[8], codigo[9], codigo[10]);
This code above seems to work, but I wonder if there is a simpler way (especially for bigger arrays)?
Clarification: I have a txt file, formatted with these containing the filenames without extension and the human filename. I'm trying to make a program that will rename these files to the correct name, as they are from a backup that failed.
EDIT: Here is the full program. I renamed the variables to make more sense, so "codigo" is now "idcode".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int i, j, k;
char value1[26], value2[70], idcode[11], filename[16], fullname[64], filenamestring[16], fullnamestring[64];
// Opening file.
FILE *nomes;
nomes = fopen("/Users/EA/Desktop/Songs/backup.txt", "rt");
if(nomes == NULL)
{
printf("Erro ao abrir backup.txt");
exit(1);
}
// Skipping beggining of file until first value.
for(i=0; i<10; i++)
{
fscanf(nomes, "%*s");
}
// Reading first value, and repetition.
while(fscanf(nomes, "%s", value1) == 1)
{
j = k = 0;
// Extracting idcode from value1.
for(i=7; i<18; i++)
{
idcode[j] = value1[i];
j++;
}
// Filling the complete filename.
sprintf(filename, "%.*s.mp4", 11, idcode);
// Reading second value, the "human" filename.
fscanf(nomes, "\n%[^\n]", value2);
for(i=6; i<70; i++)
{
fullname[k] = value2[i];
k++;
}
// Transforming filenames into strings for rename function.
strncpy(filenamestring, filename, 16);
strncpy(fullnamestring, fullname, 64);
// Renaming the files.
rename(filename, fullname);
// Skipping useless data before the next cycle.
for(i=0; i<9; i++)
{
fscanf(nomes, "%*s");
}
}
// Closing file and ending program.
fclose(nomes);
return(0);
}
It looks like you got an array of char's.
You can simply do:
sprintf(filename, "%.*s.mp4", 11, codigo)
You can read more about the %.*s specifier in this question.
If you just want to append the format ".mp4" to the end of the string the easiest way to do that is just:
strcat(filename,".mp4");
after you printed the name without the ".mp4" into it.
If you really want to use sprintf then i think this should suffice:
sprintf(filename,"%s.mp4", codigo);
Also,if you want your string to be bigger and not fixed in size you can put "\0" at the end of it(this might not work if you try to use the strings in other programming languages but c) with strcat as above,or you can do this:
memset(&filename, 0, sizeof(filename));

Searching a particular string in a large file

I am making program in C which can search for a specific string in a large .txt file and count it and then print it out. But it seems that something have go wrong, cause the output of my program is different from that of the two text editor. According to the text editor, there are totally 3000 words,in this case I search for the word "make", in that .txt file. But the output of my program is just 2970.
I cannot find out the problem of my program. So I am curios about how could a text editor search for a specific string so accurately? How do people implement that? Can any people show me some code in C?
To make things clear: that is a large .txt file, 20M or so, containing lots of characters. So I think it's not so good to read it into memory all at once. I have implement my program by splitting my program in to pieces and then scan all of those for parsing. However, it fail some way.
Maybe I should put the code here. Wait a minute please.
The code is kinda long, 70 lines or so. I have put it on my github, if you have any interest, please help. https://github.com/walkerlala/searchText
note that the only related file is wordCount.c and testfile.txt which goes like:
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
char arr[51];
int flag=0;
int flag2=0;
int flag3=0;
int flag4=0;
int pieceCount(FILE*);
int main()
{
//the file in which I want to search the word is testfile.txt
//I have formatted the file so that it contain no newlins any more
FILE* fs=fopen("testfile.txt","r");
int n=pieceCount(fs);
printf("%d\n",n);
rewind(fs); //refresh the file...
static bool endOfPiece1=false,endOfPiece2=false,endOfPiece3=false;
bool begOfPiece1,begOfPiece2,begOfPiece3;
for(int start=0;start<n;++start){
fgets(arr,sizeof(arr),fs);
for(int i=0;i<=46;++i){
if((arr[i]=='M'||arr[i]=='m')&&(arr[i+1]=='A'||arr[i+1]=='a')&&(arr[i+2]=='K'||arr[i+2]=='k')&&(arr[i+3]=='E'||arr[i+3]=='e')){
flag+=1;
//continue;
}
}
//check the border
begOfPiece1=((arr[1]=='e'||arr[1]=='E'));
if(begOfPiece1==true&&endOfPiece1==true)
flag2+=1;
endOfPiece1=((arr[47]=='m'||arr[47]=='M')&&(arr[48]=='a'||arr[48]=='A')&&(arr[49]=='k'||arr[49]=='K'));
begOfPiece2=((arr[1]=='k'||arr[1]=='K')&&(arr[2]=='e'||arr[2]=='E'));
if(begOfPiece2==true&&endOfPiece2==true)
flag3+=1;
endOfPiece2=((arr[48]=='m'||arr[48]=='M')&&(arr[49]=='a'||arr[49]=='A'));
begOfPiece3=((arr[1]=='a'||arr[1]=='A')&&(arr[2]=='k'||arr[2]=='K')&&(arr[3]=='e'||arr[3]=='E'));
if(begOfPiece3==true&&endOfPiece3==true)
flag4+=1;
endOfPiece3=(arr[49]=='m'||arr[49]=='M');
}
printf("%d\n%d\n%d\n%d\n",flag,flag2,flag3,flag4);
getchar();
return 0;
}
//the function counts how many pieces have I split the file into
int pieceCount(FILE* file){
static int count=0;
char arr2[51]={'\0'};
while(fgets(arr2,sizeof(arr),file)){
count+=1;
continue;
}
return count;
}
You can do this quite simply just by having a rolling buffer. You don't need to break the file into sections.
#include <stdio.h>
#include <string.h>
int main(void) {
char buff [4]; // word buffer
int count = 0; // occurrences
FILE* fs=fopen("test.txt","r"); // open the file
if (fs != NULL) { // if the file opened
if (4 == fread(buff, 1, 4, fs)) { // fill the buffer
do { // if it worked
if (strnicmp(buff, "make", 4) == 0) // check for target word
count++; // tally
memmove(buff, buff+1, 3); // shift the buffer down
} while (1 == fread(buff+3, 1, 1, fs)); // fill the last position
} // end of file
fclose(fs); // close the file
}
printf("%d\n", count); // report the result
return 0;
}
For simplicity I stopped short of making the search word "softer" and allocating the correct buffer and various sizes, since that wasn't in the question. And I have to leave something for OP to do.

bilingual program in console application in C

I have been trying to implement a way to make my program bilingual : the user could chose if the program should display French or English (in my case).
I have made lots of researches and googling but I still cannot find a good example on how to do that :/
I read about gettext, but since this is for a school's project we are not allowed to use external libraries (and I must admit I have nooo idea how to make it work even though I tried !)
Someone also suggested to me the use of arrays one for each language, I could definitely make this work but I find the solution super ugly.
Another way I thought of is to have to different files, with sentences on each line and I would be able to retrieve the right line for the right language when I need to. I think I could make this work but it also doesn't seem like the most elegant solution.
At last, a friend said I could use DLL for that. I have looked up into that and it indeed seems to be one of the best ways I could find... the problem is that most resources I could find on that matter were coded for C# and C++ and I still have no idea how I would do to implement in C :/
I can grasp the idea behind it, but have no idea how to handle it in C (at all ! I do not know how to create the DLL, call it, retrieve the right stuff from it or anything >_<)
Could someone point me to some useful resources that I could use, or write a piece of code to explain the way things work or should be done ?
It would be seriously awesome !
Thanks a lot in advance !
(Btw, I use visual studio 2012 and code in C) ^^
If you can't use a third party lib then write your own one! No need for a dll.
The basic idea is the have a file for each locale witch contains a mapping (key=value) for text resources.
The name of the file could be something like
resources_<locale>.txt
where <locale> could be something like en, fr, de etc.
When your program stars it reads first the resource file for specified locale.
Preferably you will have to store each key/value pair in a simple struct.
Your read function reads all key/value pair into a hash table witch offers a very good access speed. An alternative would be to sort the array containing the key/value pairs by key and then use binary search on lookup (not the best option, but far better than iterating over all entries each time).
Then you'll have to write a function get_text witch takes as argument the key of the text resource to be looked up an return the corresponding text in as read for the specified locale. You have to handle keys witch have no mapping, the simplest way would be to return key back.
Here is some sample code (using qsort and bsearch):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define DEFAULT_LOCALE "en"
#define NULL_ARG "[NULL]"
typedef struct localized_text {
char* key;
char* value;
} localized_text_t;
localized_text_t* localized_text_resources = NULL;
int counter = 0;
char* get_text(char*);
void read_localized_text_resources(char*);
char* read_line(FILE*);
void free_localized_text_resources();
int compare_keys(const void*, const void*);
void print_localized_text_resources();
int main(int argc, char** argv)
{
argv++;
argc--;
char* locale = DEFAULT_LOCALE;
if(! *argv) {
printf("No locale provided, default to %s\n", locale);
} else {
locale = *argv;
printf("Locale provided is %s\n", locale);
}
read_localized_text_resources(locale);
printf("\n%s, %s!\n", get_text("HELLO"), get_text("WORLD"));
printf("\n%s\n", get_text("foo"));
free_localized_text_resources();
return 0;
}
char* get_text(char* key)
{
char* text = NULL_ARG;
if(key) {
text = key;
localized_text_t tmp;
tmp.key = key;
localized_text_t* result = bsearch(&tmp, localized_text_resources, counter, sizeof(localized_text_t), compare_keys);
if(result) {
text = result->value;
}
}
return text;
}
void read_localized_text_resources(char* locale)
{
if(locale) {
char localized_text_resources_file_name[64];
sprintf(localized_text_resources_file_name, "resources_%s.txt", locale);
printf("Read localized text resources from file %s\n", localized_text_resources_file_name);
FILE* localized_text_resources_file = fopen(localized_text_resources_file_name, "r");
if(! localized_text_resources_file) {
perror(localized_text_resources_file_name);
exit(1);
}
int size = 10;
localized_text_resources = malloc(size * sizeof(localized_text_t));
if(! localized_text_resources) {
perror("Unable to allocate memory for text resources");
}
char* line;
while((line = read_line(localized_text_resources_file))) {
if(strlen(line) > 0) {
if(counter == size) {
size += 10;
localized_text_resources = realloc(localized_text_resources, size * sizeof(localized_text_t));
}
localized_text_resources[counter].key = line;
while(*line != '=') {
line++;
}
*line = '\0';
line++;
localized_text_resources[counter].value = line;
counter++;
}
}
qsort(localized_text_resources, counter, sizeof(localized_text_t), compare_keys);
// print_localized_text_resources();
printf("%d text resource(s) found in file %s\n", counter, localized_text_resources_file_name);
}
}
char* read_line(FILE* p_file)
{
int len = 10, i = 0, c = 0;
char* line = NULL;
if(p_file) {
line = malloc(len * sizeof(char));
c = fgetc(p_file);
while(c != EOF) {
if(i == len) {
len += 10;
line = realloc(line, len * sizeof(char));
}
line[i++] = c;
c = fgetc(p_file);
if(c == '\n' || c == '\r') {
break;
}
}
line[i] = '\0';
while(c == '\n' || c == '\r') {
c = fgetc(p_file);
}
if(c != EOF) {
ungetc(c, p_file);
}
if(strlen(line) == 0 && c == EOF) {
free(line);
line = NULL;
}
}
return line;
}
void free_localized_text_resources()
{
if(localized_text_resources) {
while(counter--) {
free(localized_text_resources[counter].key);
}
free(localized_text_resources);
}
}
int compare_keys(const void* e1, const void* e2)
{
return strcmp(((localized_text_t*) e1)->key, ((localized_text_t*) e2)->key);
}
void print_localized_text_resources()
{
int i = 0;
for(; i < counter; i++) {
printf("Key=%s value=%s\n", localized_text_resources[i].key, localized_text_resources[i].value);
}
}
Used with the following resource files
resources_en.txt
WORLD=World
HELLO=Hello
resources_de.txt
HELLO=Hallo
WORLD=Welt
resources_fr.txt
HELLO=Hello
WORLD=Monde
run
(1) out.exe /* default */
(2) out.exe en
(3) out.exe de
(4) out.exe fr
output
(1) Hello, World!
(2) Hello, World!
(3) Hallo, Welt!
(4) Hello, Monde!
gettext is the obvious answer but it seems it's not possible in your case. Hmmm. If you really, really need a custom solution... throwing out a wild idea here...
1: Create a custom multilingual string type. The upside is that you can easily add new languages afterwards, if you want. The downside you'll see in #4.
//Terrible name, change it
typedef struct
{
char *french;
char *english;
} MyString;
2: Define your strings as needed.
MyString s;
s.french = "Bonjour!";
s.english = "Hello!";
3: Utility enum and function
enum
{
ENGLISH,
FRENCH
};
char* getLanguageString(MyString *myStr, int language)
{
switch(language)
{
case ENGLISH:
return myStr->english;
break;
case FRENCH:
return myStr->french;
break;
default:
//How you handle other values is up to you. You could decide on a default, for instance
//TODO
}
}
4: Create wrapper functions instead of using plain old C standard functions. For instance, instead of printf :
//Function should use the variable arguments and allow a custom format, too
int myPrintf(const char *format, MyString *myStr, int language, ...)
{
return printf(format, getLanguageString(myStr, language));
}
That part is the painful one : you'll need to override every function you use strings with to handle custom strings. You could also specify a global, default language variable to use when one isn't specified.
Again : gettext is much, much better. Implement this only if you really need to.
the main idea of making programs translatable is using in all places you use texts any kind of id. Then before displaying the test you get the text using the id form the appropriate language-table.
Example:
instead of writing
printf("%s","Hello world");
You write
printf("%s",myGetText(HELLO_WORLD));
Often instead of id the native-language string itself is used. e.g.:
printf("%s",myGetText("Hello world"));
Finally, the myGetText function is usually implemented as a Macro, e.g.:
printf("%s", tr("Hello world"));
This macro could be used by an external parser (like in gettext) for identifying texts to be translated in source code and store them as list in a file.
The myGetText could be implemented as follows:
std::map<std::string, std::map<std::string, std::string> > LangTextTab;
std::string GlobalVarLang="en"; //change to de for obtaining texts in German
void readLanguagesFromFile()
{
LangTextTab["de"]["Hello"]="Hallo";
LangTextTab["de"]["Bye"]="Auf Wiedersehen";
LangTextTab["en"]["Hello"]="Hello";
LangTextTab["en"]["Bye"]="Bye";
}
const char * myGetText( const char* origText )
{
return LangTextTab[GlobalVarLang][origText ].c_str();
}
Please consider the code as pseudo-code. I haven't compiled it. Many issues are still to mention: unicode, thread-safety, etc...
I hope however the example will give you the idea how to start.

Why does my program read an extra structure?

I'm making a small console-based rpg, to brush up on my programming skills.
I am using structures to store character data. Things like their HP, Strength, perhaps Inventory down the road. One of the key things I need to be able to do is load and save characters. Which means reading and saving structures.
Right now I'm just saving and loading a structure with first name and last name, and attempting to read it properly.
Here is my code for creating a character:
void createCharacter()
{
char namebuf[20];
printf("First Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].fname,namebuf);
printf("Last Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].lname,namebuf);
/*Character created, now save */
saveCharacter(party[nMember]);
printf("\n\n");
loadCharacter();
}
And here is the saveCharacter function:
void saveCharacter(character party)
{
FILE *fp;
fp = fopen("data","a");
fwrite(&party,sizeof(party),1,fp);
fclose(fp);
}
and the loadCharacter function
void loadCharacter()
{
FILE *fp;
character tempParty[50];
int loop = 0;
int count = 1;
int read = 2;
fp= fopen("data","r");
while(read != 0)
{
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
}
fclose(fp);
}
So the expected result of the program is that I input a name and last name such as 'John Doe', and it gets appended to the data file. Then it is read in, maybe something like
1. Jane Doe
2. John Doe
and the program ends.
However, my output seems to add one more blank structure to the end.
1. Jane Doe
2. John Doe
3.
I'd like to know why this is. Keep in mind I'm reading the file until fread returns a 0 to signify it's hit the EOF.
Thanks :)
Change your loop:
while( fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp) )
{
// other stuff
}
Whenever you write file reading code ask yourself this question - "what happens if I read an empty file?"
You have an algorithmic problem in your loop, change it to:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
while(read != 0)
{
//read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
}
There are ways to ged rid of the double fread but first get it working and make sure you understand the flow.
Here:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
You are not checking whether the read was successful (the return value of fread()).
while( 1==fread(&tempParty[loop],sizeof*tempParty,1,fp) )
{
/* do anything */
}
is the correct way.
use fopen("data","rb")
instead of fopen("data","r") which is equivalent to fopen("data","rt")
You've got the answer to your immediate question but it's worth pointing out that blindly writing and reading whole structures is not a good plan.
Structure layouts can and do change depending on the compiler you use, the version of that compiler and even with the exact compiler flags used. Any change here will break your ability to read files saved with a different version.
If you have ambitions of supporting multiple platforms issues like endianness also come into play.
And then there's what happens if you add elements to your structure in later versions ...
For robustness you need to think about defining your file format independently of your code and having your save and load functions handle serialising and de-serialising to and from this format.

Resources