1
votes

Let's say I have a file. I read all the bytes into an unsigned char buffer. From there I'm trying to read a c string (null terminated) without knowing it's length.

I tried the following:

char* Stream::ReadCString()
{
    char str[0x10000];
    int len = 0;
    char* pos = (char*)(this->buffer[this->position]);
    while(*pos != 0)
        str[len++] = *pos++;
    this->position += len+ 1;
    return str;
}

I thought I could fill up each char in the str array as I went through, checking if the char was null terminated or not. This is not working. Any help?

this->buffer = array of bytes
this->position = position in the array

Are there any other methods to do this? I guess I could run it by the address of the actual buffer: str[len++] = *(char*)(this->buffer[this->position++]) ?

Update: My new function:

char* Stream::ReadCString()
{
    this->AdvPosition(strlen((char*)&(this->buffer[this->position])) + 1);
    return (char*)&(this->buffer[this->position]);
}

and calling it with:

printf( "String: %s\n", s.ReadCString()); //tried casting to char* as well just outputs blank string

Example File: enter image description here

4
you are trying to return a local variableAlexis
correct, for example: printf("%s\n", Stream.ReadCString());MysteryDev
Not sure to understand, let'say your buffer is [0,0,0,'H','E','L','L',O',0] and position is 3 why you are not returning &(buffer[position]) ? and position += strlen(&buffer[position])Alexis
@Alexis I already tried that, maybe I typed it wrong. I'll give it another go.MysteryDev
@Alexis It will read past it now, but it won't display it for some odd reason.MysteryDev

4 Answers

1
votes

Check this:

#include <cstring>
#include <iostream>

class   A
{
  unsigned char buffer[4096];
  int   position;

public:
  A() : position(0)
  {
    memset(buffer, 0, 4096);
    char        *pos = reinterpret_cast<char*>(&(this->buffer[50]));
    strcpy(pos, "String");
    pos = reinterpret_cast<char*>(&(this->buffer[100]));
    strcpy(pos, "An other string");
  }

   const char *ReadString()
  {
    if (this->position != 4096)
      {
        while (std::isalpha(this->buffer[this->position]) == false && this->position != 4096)
               this->position++;
        if (this->position == 4096)
          return 0;
        void    *tmp = &(this->buffer[this->position]);
        char    *str  = static_cast<char *>(tmp);
        this->position += strlen(str);
        return (str);
      }
    return 0;
  }

};

The reintrepret_cast are only for the init, since you are reading from a file

int     main()
{
  A     test;

  std::cout << test.ReadString() << std::endl;
  std::cout << test.ReadString() << std::endl;
  std::cout << test.ReadString() << std::endl;
}

http://ideone.com/LcPdFD

Edit I have changed the end of ReadString()

1
votes

str is a local c string. Any referencing pointer to str outsider the function is undefined behavior: Undefined, unspecified and implementation-defined behavior, it might or might not cause notable problem.

0
votes

Null termination is probably the best way to go as long as you're careful, but the reason its not working for you is most likely because you are returning memory that has been allocated on the stack. This memory is going to be freed as soon as you hit the return which will therefore cause undefined behaviour. Instead, allocate your chars on the heap:

char* str = new char[0x10000];

and free the memory when the caller doesn't need it anymore.

0
votes

It can be fixed with the following method. I was advancing the position, and then returning the address.

char* Stream::ReadCString()
{
    u64 str_len = strlen((char*)&(this->buffer[this->position])) + 1;
    this->AdvPosition(str_len);
    return (char*)&(this->buffer[this->position - str_len]);
}

Hope this helps anyone.