Sign in to follow this  
Decrius

[C(++)] strings in file to string in memory

Recommended Posts

Decrius    100
This should be sort of easy but I cannot grasp it... I have a file with content, the content has an 'array' of strings (just strings seperated by 0x00). I want those strings to be put in an array of char * so I can handle it further. How can I read out the buffer of the loaded file and put the strings in the array? I got it working, but not fully. I also want to add "data/" infront and ".png" at the end. int size = number of textures in the file char *buffer = an allocated piece of memory filled with the complete content of the file
char *textures[size];
                for (int i = 0; i < size; i++)
                {
                    textures[i] = buffer;
                    while (*buffer != 0x00)
                    {
                        *buffer += 96;
                        buffer++;
                    }
                    buffer++;
                    std::cout << textures[i] << "\n";
                }

                world_textures->load_textures(size, textures);
I prolly have to rewrite it to add "data/" and ".png", but how would you do that? I get confused with the pointers if its about char * ... :( Thanks, Decrius

Share this post


Link to post
Share on other sites
jyk    2094
Short answer: do it the 'hard way' (e.g. using pointers and manual memory management and C-library functions such as strcpy() and strcat()) as an exercise, then set all that aside and use std::string instead. The latter will take care of the memory management aspect of things for you, and will allow you to write more intuitive statements such as:
path = "data/" + name + ".png";
If the file is in text format, you should be able to simply extract the file names from the stream using the >> operator. If the file is binary, it's a little more complicated; in this case, I'd recommend using an existing solution such as the Boost Serialization library.

Share this post


Link to post
Share on other sites
Decrius    100
Quote:
Original post by jyk
Short answer: do it the 'hard way' (e.g. using pointers and manual memory management and C-library functions such as strcpy() and strcat()) as an exercise, then set all that aside and use std::string instead. The latter will take care of the memory management aspect of things for you, and will allow you to write more intuitive statements such as:
path = "data/" + name + ".png";
If the file is in text format, you should be able to simply extract the file names from the stream using the >> operator. If the file is binary, it's a little more complicated; in this case, I'd recommend using an existing solution such as the Boost Serialization library.


Yes, the hard way please :P. Since the texture loading function is written for char* arrays (wrote it myself) and I prefer C for some things, I need the output in the standard C format...

I can work with strcpy and strcat with normal character strings, but this is an array of pointers to character strings...not sure how to handle that...

Thanks anyways,

Share this post


Link to post
Share on other sites
nobodynews    3126
Quote:
Original post by Decrius
Yes, the hard way please :P. Since the texture loading function is written for char* arrays (wrote it myself)


Wrote it yourself? Then you can rewrite it to use std::string just as easily. But let's say for the sake of argument that you Didn't write the texture loading function. You can still use your function by calling std::string::c_str which returns a const char * that you can pass to functions that take const char *. You did write your function to be const correct at least, right? As for this:

Quote:
and I prefer C for some things, I need the output in the standard C format...


that's your prerogative, but you're really just hurting yourself and opening yourself up for a lot of easily avoidable bugs by not using std::string and likely the rest of the C++ Standard Library. Good luck with your project!

Share this post


Link to post
Share on other sites
ToohrVyk    1595
Quote:
Original post by Decrius
Yes, the hard way please :P. Since the texture loading function is written for char* arrays (wrote it myself) and I prefer C for some things, I need the output in the standard C format...


Well... let's get this done.


char *textures[size] = {0};

try
{
for (int i = 0; i < size; ++i, ++buffer)
{
const char *original = buffer;
while (*buffer != 0x00)
*buffer++ += 96;

const std::size_t len =
strlen(original) + strlen("data/") + strlen(".png") + 1;
textures[i] = new char[len];

strncpy(textures[i], "data/", len);
assert(strlen("data/") < len);

strncat(textures[i], original, len - strlen(textures[i]) - 1);
strncat(textures[i], ".png", len - strlen(textures[i]) - 1);
}

world_textures->load_textures(size, textures);
}

catch(...)
{
for (int i = 0; i < size; ++i)
delete [] textures[i];
}

for (int i = 0; i < size; ++i)
delete [] textures[i];


Share this post


Link to post
Share on other sites
ToohrVyk    1595
Quote:
Original post by MJP
I have a feeling that the code ToohrVyk posted looks an awful lot like most implementations of std::string's operator+... [smile]


Actually, no, it doesn't: it's more complex than that. I suspect most implementations of std::string concatenation (operator+=) would look something like this:

template<typename It> // Assumed Random-Access iterator
void append(It begin, It end)
{
std::size_t full = size + std:distance(begin, end);
if (full > self.capacity)
{
detail::buffer other(full);
std::copy(self.data, self.data + size, other.data);
std::swap(self, other);
}

std::copy(begin, end, self.data + size);
size = full;
}


Where 'buf' is a thin RAII wrapper around a buffer of characters.

Share this post


Link to post
Share on other sites
Decrius    100
Quote:
Original post by ToohrVyk
Quote:
Original post by Decrius
Yes, the hard way please :P. Since the texture loading function is written for char* arrays (wrote it myself) and I prefer C for some things, I need the output in the standard C format...


Well... let's get this done.

*** Source Snippet Removed ***


Thank you :), it works, now I'll examine what I did wrong :P

What does assert() do exactly? Yes, it can throw the exception, but it checks if the string is copied from one to another in this case?

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
I want those strings to be put in an array of char *


This is sort of like saying "I want those eggs to be put in a carton of eggshells which contain yolks and whites". If you have strings, why not put them in an array of, well, strings? A char* is not a string. It's a pointer; it points to some chunk of memory, where you write some sequence of characters, and do all the memory management.

Quote:
Since the texture loading function is written for char* arrays (wrote it myself)


If you wrote it yourself, you can fix it.

Quote:
and I prefer C for some things,


You prefer making things harder for yourself for no reason?

Quote:
I need the output in the standard C format...


(a) Not if you fix the function, you don't.
(b) You can always get at the underlying "const char *" representation of a string object with its .c_str() member function, nice and simple.

BTW, why on earth are you adding 96 to each character as you go? Some kind of "encryption"? Please, don't make me laugh. And what are you going to do if you want a string to actually contain ASCII character 96 (a backtick, `)? Then you'd have a zero byte in the file, and wouldn't be able to distinguish it from a null terminator.

And for that matter, why not just cut up the file as you read it (use the free function std::getline() to read into a std::string object; you can specify the 'delimiter' of your "line" to be a zero byte)?

Share this post


Link to post
Share on other sites
Decrius    100
The +96 is not an encryption at all, since its completely irrelevant for the problem I didn't explain why I use it.

Why would I write it in C++ when I don't use all those extra functions they provide? What is wrong with C? It wasn't very difficult after all, was similair difficult in C++, why the hate towards plain C if C++ doesn't add a significant ammount of usefullness?

And why would I rewrite my entire function as a WORKAROUND, since I couldn't get it to work in C? That would be a waste of time and effort.

Tell me, why would I use a canon to fire a mosquito while I could aswell hit it with my hands?

Share this post


Link to post
Share on other sites
ToohrVyk    1595
Quote:
Original post by Decrius
Why would I write it in C++ when I don't use all those extra functions they provide? What is wrong with C? It wasn't very difficult after all, was similair difficult in C++, why the hate towards plain C if C++ doesn't add a significant ammount of usefullness?


You're wrong. Writing the C code was an order of magnitude harder than C++: I'm a fluent programmer in both, yet I still had to look up the reference for strncpy and strncat to determine what their last argument represented, in addition to the effort I had to spend to make the code exception-proof. Even then, the code remains quite long, especially when the corresponding C++ code is:

const std::string path = "data/", ext = ".png";

std::string input;
std::vector<std::string> images;

while (std::getline(file,input,0) && !input.empty())
images.push_back(path + input + ext);

load_textures(images);




There are exactly zero potential overflow or memory leak issues in this code, and I made absolutely no effort to make sure of it. By comparison, the C code contained one potential memory leak (new []), four potential string overflows (strncpy, strncat, plus the size of buffer), one of which was actually present in the code before I checked the manual for strncpy again and added the assert, and one potential array overflow (since you have to pass the size alongside the array).

Quote:
And why would I rewrite my entire function as a WORKAROUND, since I couldn't get it to work in C? That would be a waste of time and effort.


Code quality improvement is not a workaround. Besides, since the C++ code is shorter and faster to write and debug, you certainly didn't waste any time or effort.

Quote:
Tell me, why would I use a canon to fire a mosquito while I could aswell hit it with my hands?


Incorrect analogy. Using C string manipulation functions in C++ at your level of skill (after all, you couldn't solve this problem on your own) is akin to hitting a mosquito with a Ming vase: you'll have trouble hitting your target, and there'll be a lot of pain if you miss. So, use your hands instead.

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