Sign in to follow this  
OneMoreToGo

Getting strings with /'s and .'s

Recommended Posts

For some reason I'm unable to get a string from a file if it contains slashes and periods. I can load this: /this/is/a/string Or this: this.is.a.string But not this: /this/is/a.string When I do I get a memory segmentation fault error. (Code 11). I got that once when I tried closing a file stream that wasn't actually open yet. I'm not sure how the two are related besides using the Ifstreams and ofstreams. What could be going wrong? Thanks for any help! :)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
most certainly there is an error with your test code. the underlying mechanisms responsible for file IO aren't to blame here. please post some code that you're trying to read the strings with. especially make sure the buffers you're reading into are included in the snippet.

Share this post


Link to post
Share on other sites
Sorry it took me so long to get back. Here's the main file:

Quote:

#include <iostream>
#include "flx_fileIO.h"

using namespace std;

int myName = 35;
int myName2 = 468;
char myString[15];
char myStringIn[127];

int main (int argc, char * const argv[]) {
FLX_purgeFileArray();
cout << "Purged array." << endl;
FLX_loadFile("file.txt", "r", myName);
cout << "Loaded file." << endl;
FLX_getString(myName, myString);
cout << "Retrieved string." << endl;
FLX_closeFile(myName);
cout << "Closed file." << endl;
cout << myString << endl;

/*
FLX_loadFile("file.txt", "w", myName2);
cout << "Input text: " << endl;
cin >> myStringIn;
FLX_writeInt(strlen(myStringIn), myName2);
FLX_writeString(myStringIn, myName2);
FLX_closeFile(myName2);
*/

return 0;
}



The FLX functions, which you will probably not be familiar with are part of FLX, a library I am making to simplify the stratedgy game development process. My output gets all the way to "Loaded File", which means it's the get string function that's tripping up.

Here's the body of the FLX_getString function.

Quote:


int FLX_getString(int flx_gs_name, char flx_gs_userWordSlot[]) {

// If this name is invalid.
int flx_gs_thisSlot = FLX_locateFileSlot(flx_gs_name);
if (flx_gs_thisSlot == -1) {
return(-1);
}
// If this name is for an empty or write slot.
if (flx_fileStreams[flx_gs_thisSlot].type[0] == ("e" || "w")) {
return(-1);
}

// And if we're ok...
flx_fileStreams[flx_gs_thisSlot].ifs >> flx_gs_userWordSlot;

return(0);
}



I should probably explain how FLX's file manager works. It uses array's for everything, and lets the user give these slots names. The use is able to manipulate that file slot with the name code. It's just like standard c++ i/o, I added these functions as an exercise to improve my file in/out understanding and to make FLX a more "all-inclusive" package.

I see nothing that could be having trouble here... I'll try using normal c i/o stuff.

Thanks!

Share this post


Link to post
Share on other sites
Well, you are certainly not simplifying anything by using C constructs. Instead of character arrays, use std::string. Instead of what I can only assume is a raw array, use std::vector/std::list (or, considering you want named "file slots," use std::map).

I am certain that you are overwriting an array boundary, whether it is in one of your strings, or in your "file manager," or somewhere else. I cannot say without the relevant code.


jfl.

Share this post


Link to post
Share on other sites
Quote:
Original post by jflanglois
Well, you are certainly not simplifying anything by using C constructs. Instead of character arrays, use std::string. Instead of what I can only assume is a raw array, use std::vector/std::list (or, considering you want named "file slots," use std::map).

I am certain that you are overwriting an array boundary, whether it is in one of your strings, or in your "file manager," or somewhere else. I cannot say without the relevant code.


jfl.


Oh please no, I have no desire to go through all the code from my file manipulation and changing it all to more of c++'s strange formats. I use struct's because they allow me to decide what properties each file has, rather than having slots in an array for every aspect, which would be annoying and require changing loads of code which I do not wish to go through again.

I've tried using cin to get characters to arrays and then output with /'s and periods. I then did so with file in manipulators. All my function does is manage an array of structs doing the exact same thing. I'm guessing somehow structs are not allowed to contain .'s and /'s, although that seems unlikely, I'm pretty confident that my code is not causing this.

Oh wait, I just realized. Damn I'm dumb smurf... my array was too small. :(

Really sorry for this! *embarrassed* Yeah... I feel reeaallly stupid right now.

Share this post


Link to post
Share on other sites
Quote:
Original post by OneMoreToGo
Oh please no, I have no desire to go through all the code from my file manipulation and changing it all to more of c++'s strange formats. I use struct's because they allow me to decide what properties each file has, rather than having slots in an array for every aspect, which would be annoying and require changing loads of code which I do not wish to go through again.


They're not "strange formats". (Besides which, you're already using the iostream library just fine.) They're carefully designed classes and functions created by very smart people *specifically to avoid problems like*

Quote:
Oh wait, I just realized. Damn I'm dumb smurf... my array was too small. :(

Really sorry for this! *embarrassed* Yeah... I feel reeaallly stupid right now.


Heck, the fact that I see this in your code:


if (flx_fileStreams[flx_gs_thisSlot].type[0] == ("e" || "w")) {


tells me you're not qualified to reinvent the wheel. (Hint: it doesn't do what you think it does. "e" || "w" simplifies to 1, and anyway, assuming that 'type' is a char**, you can't just compare strings like that: the comparison would compare the char* pointer values, not the pointed-at data.)

I'll make you an offer you can't refuse: PM me the whole flx_fileIO module (or instructions for getting it - just how big is that anyway o_O), and I'll rewrite it for you free, over the weekend, to the best of my ability.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Quote:
Original post by OneMoreToGo
Oh please no, I have no desire to go through all the code from my file manipulation and changing it all to more of c++'s strange formats. I use struct's because they allow me to decide what properties each file has, rather than having slots in an array for every aspect, which would be annoying and require changing loads of code which I do not wish to go through again.


They're not "strange formats". (Besides which, you're already using the iostream library just fine.) They're carefully designed classes and functions created by very smart people *specifically to avoid problems like*

Quote:
Oh wait, I just realized. Damn I'm dumb smurf... my array was too small. :(

Really sorry for this! *embarrassed* Yeah... I feel reeaallly stupid right now.


Heck, the fact that I see this in your code:


if (flx_fileStreams[flx_gs_thisSlot].type[0] == ("e" || "w")) {


tells me you're not qualified to reinvent the wheel. (Hint: it doesn't do what you think it does. "e" || "w" simplifies to 1, and anyway, assuming that 'type' is a char**, you can't just compare strings like that: the comparison would compare the char* pointer values, not the pointed-at data.)

I'll make you an offer you can't refuse: PM me the whole flx_fileIO module (or instructions for getting it - just how big is that anyway o_O), and I'll rewrite it for you free, over the weekend, to the best of my ability.



Type, is a char[0], not a pointer. It is not taken as an argument to a function, but is accessed directly from multiple different functions, and in no way by the user. If they try to I'll slap them. ;) I'd love to take up your offer though. And believe me, you'd get a large credit in the end, that's for sure. :)

I'll PM you a link to the code.

Share this post


Link to post
Share on other sites
btw,

"e" != 'e'

one is a string constant ("e") and the other is a character literal ('e'). One has an ascii value of something like 101 (that's the 'e'), and the other has some 32-bit address (I'm assuming a 32-bit system)

Share this post


Link to post
Share on other sites
BTW,

Before you read any of the code I send back to you, try to write any more code, or in any way represent that you know anything about C or C++, you need to read this and understand it in full.

Share this post


Link to post
Share on other sites
Quote:
Original post by wyrzy
btw,

"e" != 'e'

one is a string constant ("e") and the other is a character literal ('e'). One has an ascii value of something like 101 (that's the 'e'), and the other has some 32-bit address (I'm assuming a 32-bit system)



I am not comparing those two. As long as the user supplies "e", all my code will check for "e". 'e' is not involved. I was unaware of the fact that you could not use nested or statements though;

if (whatever == ("a" || "q") -> bad?

Thanks!

Share this post


Link to post
Share on other sites
Quote:
Original post by OneMoreToGo
if (whatever == ("a" || "q") -> bad?


Indeed. This sentence means "if whatever is equal to ("a" || "q")", not "if whatever is equal to "a" or "q"". Since "a" is not NULL and "q" is not NULL, ("a" || "q") is really (!NULL || !NULL) ie (true || true) ie true. So far

whatever == ("a" || "q") ==> whatever == true

To enforce what Zahlman said (he doesn't know it but he is the high priest of my own personnal religion), std::string and other "c++'s strange formats" have been created to help you. The C and C++ languages are hard enough, you don't have to lose your time to try to replicate something that already exists in a well tested, standard library.

And std::string is really the roxors :)

Share this post


Link to post
Share on other sites
I shall attempt to keep that in mind, however, would it take a lot of adaptation to install the string method? I'll try to use in future code, but for the moment, I'll just convert all my "e" to 'e', a temporary fix for some code which is comparatively useless (when looked at besides c++'s original file i/o streams). Oh well. :)

Share this post


Link to post
Share on other sites
Quote:
Original post by OneMoreToGo
I shall attempt to keep that in mind, however, would it take a lot of adaptation to install the string method? I'll try to use in future code, but for the moment, I'll just convert all my "e" to 'e', a temporary fix for some code which is comparatively useless (when looked at besides c++'s original file i/o streams). Oh well. :)

The time it takes to learn and use std::string and other Standard Library constructs will be much less than the time wasted debugging problems like the ones you are having now.


jfl.

Share this post


Link to post
Share on other sites
Quote:
Original post by OneMoreToGo
I shall attempt to keep that in mind, however, would it take a lot of adaptation to install the string method? I'll try to use in future code, but for the moment, I'll just convert all my "e" to 'e', a temporary fix for some code which is comparatively useless (when looked at besides c++'s original file i/o streams). Oh well. :)



Quote:
/Users/gareth/Desktop/flx testing/FLX_Test_IO/flx_fileIO.h:95: error: ISO C++ forbids comparison between pointer and integer


*sigh* Point taken. I'll google it.

Share this post


Link to post
Share on other sites
Did you miss the part where we explained the logical error? There is no set of types (unless you implemented one yourself, and it would be probably roundly considered a very bad idea even if it actually worked according to spec) you can use such that OR-ing two values, and then comparing for equality to the result, is equivalent to checking whether you have one of the two values.

You don't know what you're doing, and you need to take several steps back and learn things properly. Including the standard library (not just the streams) this time. It's called the standard library for a reason.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Did you miss the part where we explained the logical error? There is no set of types (unless you implemented one yourself, and it would be probably roundly considered a very bad idea even if it actually worked according to spec) you can use such that OR-ing two values, and then comparing for equality to the result, is equivalent to checking whether you have one of the two values.

You don't know what you're doing, and you need to take several steps back and learn things properly. Including the standard library (not just the streams) this time. It's called the standard library for a reason.


The error was meant as a bit of humor, as in "You know what? I'm sick of this, I give in. I'll do it your way".

Is that what you were reffering to? The problem I see, is that I have always in the past used double-quotes around my letters that were always in char format. It's the way I was taught. Now a couple of years later, I'm going through SDL learning new things on a basis that appears to be wrong. I have a book on C++, and although it never mentioned the std:: operator (neither did the course I took, I swear! And everything worked too!) it seems fine in all other regards, so I'll go back and review arrays & pointers. I've googled a bit about string operators, and they seem useful. Do they comply with standard sizeof() & strlen() commands? I'll just test that myself though, so no worries.

Thanks for all your help! Hopefully I won't be back with to many bothersome problems for a while. (Yeah right.)

Share this post


Link to post
Share on other sites
Quote:
Original post by OneMoreToGo
I have a book on C++, and although it never mentioned the std:: operator (neither did the course I took, I swear! And everything worked too!) it seems fine in all other regards, so I'll go back and review arrays & pointers. I've googled a bit about string operators, and they seem useful. Do they comply with standard sizeof() & strlen() commands? I'll just test that myself though, so no worries.


To be able to use things correctly, you have to know what they are. Talking vaguely about "operators" and "commands" probably has a lot to do with why you're confused. Also, your C++ book is evidently several years out of date and needs to be thrown away, and most C++ programming courses out there that I've heard about are pretty much garbage as well. Sorry, but that's the state of things.

std:: is a namespace. Namespaces are a way of decorating identifiers (that's a catch-all term that includes variable names, function names and class/struct names - and probably other stuff I forgot) so that instead of using "foo_" prefixes to avoid name collisions, you use "foo::". But it's actually much better than that, because (a) they're a language construct that the compiler can actually do some checking with, and (b) you can set things up such that certain blocks of code omit the "foo::" for convenience, when it is not needed to avoid collisions. For example, suppose you made a "2d vector" class (of the sort that is reinvented a gazillion times by everyone; basically it just represents a pair of X and Y coordinates), and called it 'vector', and wanted to store a std::vector of them. In the code using that vector, you'd have to write "std::vector<vector>", in order to make things clear to the compiler. (Perhaps you would be smart enough to put your vector class in its own namespace, too; then you'd qualify that name as well.) But in some other source file of the same project that *didn't* use the local vector class but still used the standard library vector container, you could get away with "using std::vector;" at the top and "vector<int>" everywhere else.

'std::string' is a class. Thus you can declare variables of type std::string; each of these might be called "a std::string instance" or "a std::string object". It represents textual information. In C++, classes and structs can provide "member functions", as well as operator overloads . When you write "cout << foo;", 'cout' is a global object of type std::ostream, and you are invoking the overloaded operator<<(std::ostream&, T) for T = whatever type 'foo' happens to have. This is the same sort of process as when you write "foo + bar" and it invokes operator+(int, int) (except that there isn't really such a function in a library somewhere; the compiler just directly emits the appropriate machine code) if foo and bar are both ints, or operator+(const std::string&, const std::string&) if foo and bar are both std::strings. Note that the operator+ in question yields another std::string object which represents the concatenation of those two input strings. You can't directly, or even with a relatively small amount of work, do that properly with char*'s.

A single-quoted string in your program, like 'a' or '\n', is a "character literal". That is to say, a single byte value. (Back when all this stuff was designed, "characters" and "bytes" were considered equivalent. Now that we have Unicode, huge monkey wrenches are thrown in to that system.) It's a value that could be assigned to a variable of type char, which is an integral numeric type. When output, the numeric value is translated into a character via the ASCII table.

A double-quoted string in your program is a "string literal". What happens when you write that is that the compiler embeds the contained sequence of characters into the executable's data segment, and puts a zero-valued character ('\0') at the end as well. Then, in an expression using the string literal, that literal becomes a value of type char* (pointer to char), which points at (has a value which is the memory address of) the beginning of that sequence of characters. So a string literal is a completely different thing from a character literal, even if the string happens to be only "one character long" (note that actually two bytes are used in the static storage, because of the aforementioned 'null terminator').

sizeof is an operator. It yields, *at compile-time*, the number of bytes that are needed to represent the provided variable or type, using the *static* type.

Note that a character *array* is different from a character *pointer* - in a few ways. You need to read this. Example:


#include <iostream>
using namespace std;
int main() {
char foo[16];
char* bar = foo; // that causes bar to point to the beginning of the foo storage
cout << sizeof(foo) << ' '
<< sizeof(char[16]) << ' '
<< sizeof(bar) << ' '
<< sizeof(char*) << endl;
}


You *can* use sizeof() on any variable or type, but it is rarely something that a beginning programmer ought to find useful.

strlen() is a function. It accepts a specific argument type (const char*), so that's all you can pass to it. It's intended for figuring out the length of a "string" represented by a char*, in the way that string literals represent things. It does this by checking character values, starting at the provided location and advancing forward through memory, until it finds a zero byte (such as the one automatically inserted at the end of a string literal).

The std::string object does provide a way to extract a const char* representing its internal buffer: its .c_str() member function. This allows you to pass the data to some C APIs. However, you would not want to do it with strlen(), for at least three reasons:

1) It would be terminally retarded to do so, because the std::string object already provides a function that does that directly: its .length() member function.

2) You would lose efficiency: the std::string object already includes a length count, which is only updated when something happens that might change the string length, so all its .length() member does is return the value there. By contrast, calling strlen() requires searching through memory over the entire length of the string - every time you call it, because the information didn't get remembered anywhere.

3) You could get a wrong answer, because std::strings are capable of holding zero bytes within the "real" string data, whereas char* strings basically aren't - if you tried to make a string "hello\0world", then strlen() would stop at the *first* \0 it saw, and report a length of 5, as if all you had was "hello".

Share this post


Link to post
Share on other sites
Wow... thanks for explaining that in such detail. You might as well have written a book for me. ;)

Well, as much as I'm a cheap guy, it looks like time to get a new reference.

On a completely unrelated note:

Wow, I just tried Code::Blocks IDE. Amazing. I love it. Not only is it free, but it has built in templates for OpenGL, OGRE and SDL (and others). A nice interface, support for multiple compilers... and did I mention it was free? ;)

Once again, Thanks!

Share this post


Link to post
Share on other sites
Quote:
Original post by OneMoreToGo
Wow... thanks for explaining that in such detail. You might as well have written a book for me. ;)

Well, as much as I'm a cheap guy, it looks like time to get a new reference.

On a completely unrelated note:

Wow, I just tried Code::Blocks IDE. Amazing. I love it. Not only is it free, but it has built in templates for OpenGL, OGRE and SDL (and others). A nice interface, support for multiple compilers... and did I mention it was free? ;)

Once again, Thanks!


I really enjoyed Code::Blocks while I used it. It was easy to set up, and had tons of features like a rusimentary intellisense and a decent debugger. I would also look at the Microsoft Visual C++ Express edition. It definately is a bit bett with debugging and such. However, since you already are using Code::Blocks, you might as well stick with it.

Share this post


Link to post
Share on other sites
I actually have the Express Edition MS Visual C++ too. Unfortunatly, it's the only one I know how to set up SDL with. I'll have to explore Code::Block's presets to find out where it wants the libs to go.

But in the end, I'm not gonna do anything serious with either. I use Mac OS X with xCode for all my development, just to ignore Windows's absolutely horrible library system.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this