1

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

MysteryDev
  • 610
  • 2
  • 12
  • 31

4 Answers4

1

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.

Community
  • 1
  • 1
lulyon
  • 6,707
  • 7
  • 32
  • 49
1

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()

Alexis
  • 2,149
  • 2
  • 25
  • 39
  • I attempted and failed with reinterpret_cast, what's the difference from that and regular casting anyways? – MysteryDev Jul 23 '13 at 08:21
  • check this new version and for the cast: http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-and-reinterpret-cast-be-used . But reinterpret_cast is a stronger cast (and closer to a cast C) than static_cast – Alexis Jul 23 '13 at 08:27
  • While I Like your answer for my old method, this seems more suitable: char* Stream::ReadCString() { this->AdvPosition(strlen((char*)&(this->buffer[this->position])) + 1); return (char*)&(this->buffer[this->position]); } Is there a way to display the string using this method? – MysteryDev Jul 23 '13 at 08:34
  • Your answer is basically like mine, except you don't move position but AdvPosition. If you can't display anything is that your returning the wrong adress or something like that. And you are in c++ try to avoid the use of printf :) – Alexis Jul 23 '13 at 08:37
  • tbh printf is easier to use than std::cout imo haha – MysteryDev Jul 23 '13 at 08:40
  • I figured out my problem! I'm advancing the position and then returning the address #dumbme – MysteryDev Jul 23 '13 at 08:44
0

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.

Joseph Pla
  • 1,600
  • 1
  • 10
  • 21
  • The string in the file is already null termined. So I guess I could just get the address of the current position. I'm just having trouble displaying now. – MysteryDev Jul 23 '13 at 08:11
  • From address of first pos to null terminator, yeah. I'm still having troubling understanding what you're trying to do :P but good luck! – Joseph Pla Jul 23 '13 at 08:13
  • I'm reading all the contents of a file and storing it in a byte array (unsigned char*) After that I begin to read the data within. Here is my file http://puu.sh/3JC0B/f69dc57519.png . I am trying to display "entry_n" and advance the position to the byte after it. I can successfully advance the position, but the string won't display with printf("%s\n", stream.ReadCString()); – MysteryDev Jul 23 '13 at 08:16
0

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.

MysteryDev
  • 610
  • 2
  • 12
  • 31