File I/O
ma3stro

I couldn't figure out how to solve these problems:

1. Getting values from a text file with fscanf, resetting file content, then writing down the new values using fprintf.(the new values should start at the top of the file - rewind() function did not work)

2. How can I print a USTR format to a text file?

Edgar Reynaldo

Once you're done reading the file, close it, and then either delete it or open it in write only mode. That will reset the file contents. Otherwise, you can only overwrite or append, but not truncate.

And what do you mean rewind didn't work? Post code, and the text file it is supposed to be working on if necessary.

Audric

For 1), you need something like ftruncate() to reset the (disk) size of a file that is already open in "w+" mode. If it's not available on your platform, you can still use the universal method of :
- open the file in "r" mode,
- read what you need,
- close it,
- open the same file in "w" mode this time.
- write what you need
- close

Aikei_c

For 2, there are allegro functions which convert ALLEGR0_USTR to c string.

ma3stro

I tried what you told me but it doesn't seem to work on this:

.
.
.

if(code == Bus[5].code)
file1 = fopen("list6.txt", "a+");

for(int j=0; j<32; j++)
fscanf(file1, "%d %c\n", &Seat[j].no, &Seat[j].type);

fclose(file1);

.
.
.

The reason I can't open file in "r" mode is beacuse I'm using the struct values and they're just two members of the struct. And if I use "a+" mode when I reopen the file it starts writing at the end.

It's perfectly reading, when I use the code above. I don't now what to do at the writing part. Whenever I use the "rewind(file1)", program crashes.

Evert
Quote:

The reason I can't open file in "r" mode is beacuse I'm using the struct values and they're just two members of the struct.

I have no idea what you're trying to say here.

If you intend to read stuff from a file (as you do with fscanf), open the file with "r". If you intend to write stuff to the file (with fprintf, say), open it with "w" (or "a" if you want to append to the end of the file). If you want to be able to do both, add "+" to the string (note that there's a difference between "r+" and "w+", at least according to the man page; I've never used either).

Quote:

Whenever I use the "rewind(file1)", program crashes.

Just to make sure: you didn't close the file first (with fclose()), did you?

ma3stro

I should be reading "Bus[].no" and "Bus[].type" from the file but there are other members in struct Bus. At first I tried to use "fwrite()" but it writes down the whole struct members and I don't need that happen.

If I open the file in "r" mode it will always read the first line. I'm opening it in "a+" so I can read all the "Bus[1].type, Bus[2].type ..." in a for loop.

Program reads the file correctly, there's no problem at this point. But when it comes to writing, it appends new values to the end of the file.

And I used the rewind() function before closing the file but I got a fatal error.

Gabriel Campos

Double check the loop of your program. And post some code, so we can help!

Edgar Reynaldo
ma3stro said:

If I open the file in "r" mode it will always read the first line.

What? You can seek with fseek and fsetpos. But you have to know where in the file you should seek to.

Quote:

I'm opening it in "a+" so I can read all the "Bus[1].type, Bus[2].type ..." in a for loop.

Open it in "r+". That is the read/write mode. If you want to append to the end, use fseek(myfile , 0 , SEEK_END); to move to the end of the file.

rewind shouldn't crash unless you've passed it an invalid FILE*.

Audric

The file appears to be text ("list6.txt", fscanf() with %d format), so there is no guarantee that the written strings are as long as the previous ones.
I expect trouble if the file is not explicitly truncated. (specifically : if you rewrite only 200 bytes of a 220byte file, the last 20 ones will still be there)

ma3stro

Thank you all for your help. The file reading & writing parts are working just fine. (I used fseek() function)

I haven't found a solution for the 2nd question yet. I had a look at the manual but couldn't figure out which one to use. There is "al_ustr_append_cstr()" function but not the opposite one.

In my project I'm using:

.
.
ALLEGRO_USTR *date= al_ustr_new("");
char *Date;
.
.

I'm getting date from user then print it on the screen. Now I need to assign "date" to "Date" in order to write it on the file. I tried "al_ustr_insert_cstr(date, 0, Date);" but got an error. What am I doing wrong?

Edgar Reynaldo
ma3stro
#SelectExpand
1ALLEGRO_USTR *date= al_ustr_new(""); 2ALLEGRO_USTR *name= al_ustr_new(""); 3ALLEGRO_USTR *tel = al_ustr_new(""); 4 5char *departure; 6char *arrival; 7char *cost; 8char *time; 9char *bus_code; 10char *gender; 11const char *Date; 12const char *Tel; 13const char *Name; 14. 15. 16. 17Date= al_cstr(date) 18Name= al_cstr(name); 19Tel = al_cstr(tel); 20. 21. 22. 23if(mouse[B1]) 24{ 25 for(int i= 0; i < 32; i++) 26 if(state.x >= Seat[i].x && (state.x <= Seat[i].x + 30) && state.y >= Seat[i].y && (state.y <= Seat[i].y + 30)) 27 { 28 if(Seat[i].type == 'E') 29 al_draw_filled_rectangle(Seat[i].x, Seat[i].y, (Seat[i].x + 30)(Seat[i].y + 30), al_map_rgb(200,200,200)); 30 31 file2 = fopen("passengers.txt", "a+"); 32 33 fprintf(file2, "%s %s %s %s %s %s %s %s %d\n",Name, Tel, gender, Date, time, departure, arrival, bus_code, i+1); 34 35 fclose(file2); 36 37 if(gender == "Male") 38 Seat[i].type = 'M'; 39 else if(gender == "Female") 40 Seat[i].type = 'W'; 41 42 } 43}

Program crashes when it comes to "fprintf()" line. Is there any incompatiblity between CString, const char* and '%s' ?

taron 
if(gender == "Male")
      Seat[i].type = 'M';
    else if(gender == "Female")
      Seat[i].type = 'W';

This won't work, you're comparing the pointers, not the values they point to.
Use strcmp or strncmp to compare two C strings.

 file2 = fopen("passengers.txt", "a+");

    fprintf(file2, "%s  %s  %s  %s  %s  %s  %s  %s  %d\n",Name, Tel, gender, Date, time, departure, arrival, bus_code, i+1); 
                
    fclose(file2);

Open the file once, write all the data you need, then close the file.
Don't repeatedly open and close the file every iteration.

ma3stro said:

Program crashes when it comes to "fprintf()" line. Is there any incompatiblity between CString, const char* and '%s' ?

Are you sure none of your strings NULL? Or maybe you don't have write access to the passengers.txt file.

ma3stro
taron said:

if(gender == "Male")
Seat[i].type = 'M';
else if(gender == "Female")
Seat[i].type = 'W';

This won't work, you're comparing the pointers, not the values they point to.
Use strcmp or strncmp to compare two C strings.

I use ChooseGender() function before the code above. It process "char *gender" value whether user choose male or female. (e.g. If user clicks male button "gender" will be "Male"). Does that cause a problem?

taron said:

Are you sure none of your strings NULL? Or maybe you don't have write access to the passengers.txt file.

I moved "fopen()" function somwhere else it didn't cause an error.

taron said:

Open the file once, write all the data you need, then close the file.
Don't repeatedly open and close the file every iteration.

Thanks, that's more efficient but still have problem at "fprintf()" line.

Aikei_c

Did you change the ALLEGRO_USTR* after converting it to const char*? If you did, the pointer to const char* became invalid after that.
How does it crash? What does the compiler say?
EDIT: you don't even need to make this strange thing with declaring two different variables for one string.
If you want to pass ustr to fprintf, you just do this:

file = fopen("file.txt", "w");
ALLEGRO_USTR* uString = al_ustr_new("Hi!");
frintf(file,"%s",al_cstr(uString));

ma3stro
Aikei_c said:

Did you change the ALLEGRO_USTR* after converting it to const char*? If you did, the pointer to const char* became invalid after that.
How does it crash? What does the compiler say?

No, I did not change it. And the error is:

Unhandled exception at 0x55b913af (msvcr100d.dll) in Ticket_Automation.exe: 0xC0000005: Access violation reading location 0x000001b3.

Aikei_c said:

EDIT: you don't even need to make this strange thing with declaring two different variables for one string.
If you want to pass ustr to fprintf, you just do this:

file = fopen("file.txt", "a");
ALLEGRO_USTR* uString = al_ustr_new("Hi!");
frintf(file,"%s",al_cstr(uString));

Ok. I will try that.

LennyLen

Another way you could check what is crashing is to just initially fprintf a string literal such as "Hello World" and make sure that works fine. Then add your other variables until you work out which one is causing the crash. That might give you a hint as to where the problem lies.

ma3stro
Aikei_c said:

file = fopen("file.txt", "w");
ALLEGRO_USTR* uString = al_ustr_new("Hi!");
frintf(file,"%s",al_cstr(uString));

That didn't work either.

I changed this,

fprintf(file2, "%s %s %s %s %s %s %s %s %d\n",Name, Tel, gender, Date, time, departure, arrival, bus_code, i+1);

to this:

fprintf(file2, "%d\n" i+1);

and there weren't any problems at all. So it's the strings that cause the error.

LennyLen

Does this work:

fprintf(file2, "%s\n", al_cstr(al_ustr_new("Hello World!")));

ma3stro
LennyLen said:

Does this work:

fprintf(file2, "%s\n", al_cstr(al_ustr_new("Hello World!")));

Yes, it does.

LennyLen

Then the problem is with your ALLEGRO_USTR values, somewhere in the code you haven't shown us.

ma3stro

This is how I use one of the ALLEGRO_USTR variables:

#SelectExpand
1ALLEGRO_USTR *date= al_ustr_new(""); 2int pos = (int)al_ustr_size(date); 3. 4. 5if(!done) // If user hits enter done will be true 6{ if(STATE == DATE) 7 if(events.keyboard.unichar >= 32) 8 { 9 pos += al_ustr_append_chr(date, events.keyboard.unichar); 10 } 11 else if(events.keyboard.keycode == ALLEGRO_KEY_BACKSPACE) 12 { 13 if(al_ustr_prev(date, &pos)) 14 al_ustr_truncate(date, pos); 15 } 16. 17. 18. 19if(STATE == DATE) 20 { 21 al_draw_ustr(font, al_map_rgb(0,0,0), 260, 21, 0, date); 22 } 23. 24. 25. 26if(mouse[B1]) 27 { 28 file2 = fopen("passengers.txt", "a+"); 29 30 for(int i= 0; i < 32; i++) 31 if(state.x >= Seat[i].x && (state.x <= Seat[i].x + 30) && state.y >= Seat[i].y && (state.y <= Seat[i].y + 30)) 32 { 33 if(Seat[i].type == 'E') 34 al_draw_filled_rectangle(Seat[i].x, Seat[i].y, (Seat[i].x + 30)(Seat[i].y + 30), al_map_rgb(200,200,200)); 35 36 37 fprintf(file2, "%s %s %s %s %s %s %s %s %d\n",al_cstr(name),al_cstr(tel), gender, al_cstr(date), time, departure, arrival, bus_code, i+1); 38 39 40 if(gender == "Male") 41 Seat[i].type = 'M'; 42 else if(gender == "Female") 43 Seat[i].type = 'W'; 44 45 } 46 fclose(file2); 47 } 48. 49. 50. 51al_ustr_free(date);

Aikei_c

Use just one argument: al_cstr(name). Does it work? If not, try to understand, why. If it doesn't add another argument. Does it work?..
Keep on until you identify your problem.

ma3stro

I tried all the parameters one by one and found that "gender" value is the problem. The others are working fine.

taron said:

if(gender == "Male")
Seat[i].type = 'M';
else if(gender == "Female")
Seat[i].type = 'W';
This won't work, you're comparing the pointers, not the values they point to.
Use strcmp or strncmp to compare two C strings.

I think this is where things have gone wrong.

For strcmp(), do I have to create another string variable ( e.g. char *str = "Male" ) and compare those two(gender and str)?

Aikei_c

No, it can't be that, since 1) it happens after printf, 2) it doesn't change gender in any way.
If gender causes the problem then the gender pointer doesn't point to valid text data. Where do you assign value to gender? Problem is there somewhere.
To compare c strings you do this:

if (strcmp(gender,"Male") == 0) //if gender is "Male"
   //do something

ma3stro
#SelectExpand
1void ChooseGender(ALLEGRO_MOUSE_STATE state) 2{ 3 if(mouse[B1]) 4 if(state.x >= 100 && state.x <= 113 && state.y >= 112 && state.y <= 125 ) 5 { 6 al_draw_filled_rectangle(100, 112, 113, 125, al_map_rgb(0,0,0)); 7 gender = "Male"; 8 } 9 else if(state.x >= 200 && state.x <= 213 && state.y >= 112 && state.y <= 125 ) 10 { 11 al_draw_filled_rectangle(200, 112, 213, 125, al_map_rgb(0,0,0)); 12 gender = "Female"; 13 } 14 15}

I am using this function to get user gender.

I tried something else:

I changed "char *gender" to "char gender", "Male" to 'm' , "Female" to 'f' and %d to %c. It worked but 'â' was written in the file not 'f' or 'm'.

EDIT: strcmp() didn't work either.

Edgar Reynaldo

You're not listening. You can't compare const char* by using the equivalence operator. That compares the addresses they store, not the data at those addresses. That's why you have to use strcmp.

ma3stro

You're not listening. You can't compare const char* by using the equivalence operator. That compares the addresses they store, not the data at those addresses. That's why you have to use strcmp.

Why wouldn't I listen while seeking for help? I wrote in my last message, I used strcmp() but it didn't work.

I used this:

#SelectExpand
1int value; 2. 3. 4. 5void ChooseGender(ALLEGRO_MOUSE_STATE state) 6{ 7 if(mouse[B1]) 8 if(state.x >= 100 && state.x <= 113 && state.y >= 112 && state.y <= 125 ) 9 { 10 al_draw_filled_rectangle(100, 112, 113, 125, al_map_rgb(0,0,0)); 11 value = 0; // Male 12 } 13 else if(state.x >= 200 && state.x <= 213 && state.y >= 112 && state.y <= 125 ) 14 { 15 al_draw_filled_rectangle(200, 112, 213, 125, al_map_rgb(0,0,0)); 16 value = 1; //Female 17 } 18 19} 20. 21. 22. 23if (value == 0) 24 cinsiyet = "Male"; 25 else 26 cinsiyet = "Female";

and it worked! ;D Not the efficient way though.

Thomas Fjellstrom

That's actually more efficient than comparing strings.

Edgar Reynaldo
ma3stro said:

Why wouldn't I listen while seeking for help? I wrote in my last message, I used strcmp() but it didn't work.

Sorry, I didn't see your edit. What do you mean, strcmp didn't work? How were you using it? It returns a negative number, 0, or a positive number based on the ascii collating sequence. Negative if the first string comes before, 0 if they are equivalent, and positive if the first string comes after the second.

I think your problem is that you are thinking of const char* as if they are strings. They really aren't. They are pointers to an array of char. I used to think that way when I first started using C++. You would think you could just compare them with the equivalence operator, and you can, but that only compares the addresses they store. And curiously enough, if ("string" == "string"); is valid code, but it is comparing two static addresses. Literal strings are usually allocated statically by the compiler, meaning there is usually only one instance of "string" even if you reference it more than once.

ma3stro

Well, I thought it worked but it was not. Program always saves passengers as "Female" because the if statement doesn't provide '0' then it goes for else. If I change 'else' to 'else if' error will be back.

I think the problem is in 'ChooseGender()'. Mouse[B1] becomes true just before program reaches to function line and 'mouse.state' cannot catch the coordinates and it always returns false.

Edgar Reynaldo

If you don't mind, I'd like to see your latest code.

Here's how I would check for gender equivalence.

bool male = true;

male = (expression_with_condition_for_being_male);

const char* gender = (male?"Male":"Female");
// this is the same as if you said
// if (male) {gender = "Male";} else {gender = "Female";}

al_draw_textf(font , allegro_color , x , y , "Gender = %s" , gender);

ma3stro

If you don't mind, I'd like to see your latest code.

Here's how I would check for gender equivalence.

bool male = true;

male = (expression_with_condition_for_being_male);

const char* gender = (male?"Male":"Female");
// this is the same as if you said
// if (male) {gender = "Male";} else {gender = "Female";}

al_draw_textf(font , allegro_color , x , y , "Gender = %s" , gender);

Sorry for not responding. I handed in the project on Tuesday. I used a boolean type variable(male) and deleted the string comparison part(which was no longer necessary).

Thank you all for your help, I appreciate it!

Thread #613391. Printed from Allegro.cc