For context, I'm rewriting the string
class in C to use on microcontrollers, specifically Arduino, so that it doesn't use the standard library functions not supported by Arduino.
I've looked at several answers here that show how to pop a char off a char*
. However, within my function it doesn't seem to correctly edit the char*
.
My string class
#include <stdlib.h> // malloc
namespace micro_std {
class string {
private:
const int MAX_SIZE = 4096; // Maximum size on 16bit controllers.
char* data = nullptr;
int _length = 0;
public:
string(char* data) {
this->data = data;
for (int i = 0; data[i] != '\0'; i )
_length ;
}
int size(void) const { return _length; }
int length(void) const { return _length; }
int max_size(void) const { return MAX_SIZE; }
bool empty(void) const { return _length == 0; }
char at(int index) const { return data[index]; }
char back(void) const { return data[_length - 1]; }
char front(void) const { return data[0]; }
char* str(void) const { return data; }
void clear(void) { _length = 0; data = nullptr; }
// removed for brevity //
char pop_back(void) {
_length--;
char character = data[_length];
data[_length] = '\0';
return character;
}
// removed for brevity //
};
}
And how I'm testing my code, specifically the pop_back
function.
#include <stdio.h> // printf
#include "micro_std/string.h"
int main(int argc, char** argv) {
micro_std::string x = "abcdef";
// Testing pop_back function
printf("%d %s\n", x.length(), x.str());
for (int i = 0; i < 5; i ) {
char res = x.pop_back();
printf("%d %c %s\n", x.length(), res, x.str());
}
//printf("%s\n", x.str());
return 0;
}
And, if needed, my compiler arguments
g -w -std=c 2a -O3 program.cpp -o program
Running this program gives me the following output:
6 abcdef
5 f abcdef
4 e abcdef
3 d abcdef
2 c abcdef
1 b abcdef
Instead of the output I want:
6 abcdef
5 f abcde
4 e abcd
3 d abc
2 c ab
1 b a
Where the output is formatted like "(length) (char popped) (result string)". Why isn't the data member data
being altered when calling the pop_back
function?
CodePudding user response:
Why isn't the data member data being altered when calling the pop_back function?
Even if the code compiles (which it shouldn't, since you are trying to construct x
with a string literal, which is a const char[]
array that cannot be assigned to a non-const char*
), x
would be pointing its data
member at a string literal, thus data[_length] = '\0';
inside of pop_back()
would invoke Undefined Behavior trying to alter read-only memory.
To make your code work, you MUST make a copy of the input data, eg:
#include <stdlib.h> // malloc
namespace micro_std {
class string {
private:
const int MAX_SIZE = 4096; // Maximum size on 16bit controllers.
char _data[MAX_SIZE];
int _length = 0;
public:
string(const char* str) {
for (int i = 0; str[i] != '\0'; i) {
data[i] = str[i];
_length;
}
data[_length] = '\0';
}
...
void clear(void) { _length = 0; }
...
};
}