Home > Enterprise >  Why isn't my char* shrinking after popping a char
Why isn't my char* shrinking after popping a char

Time:03-06

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; }
           ... 
    };
}
  • Related