-1

I used to create my own printf.

But for some format specifier I had to create, I need a convert function.

I found this code on a specific website, I can give you the link if you want to, but I do not understand why they use a buffer and how does it work.

why ptr could'nt be : *ptr = respresentation[num % base]

#include <stdio.h>
#include <stdarg.h>
    
char* convert(unsigned int num, int base){
   char Representation[] = "0123456789ABCDEF";
   char buffer[50];
   char* ptr = nullptr;

   ptr = &buffer[49];
   *ptr = '\0';

    while(num != 0){
        *--ptr = Representation[num % base];
        num = num / base;
    }

    return(ptr);
};
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
Bat_Under
  • 1
  • 2
  • 2
    Please don't fall too deep into the [cargo cult programming](https://en.wikipedia.org/wiki/Cargo_cult_programming) trap. If you don't understand the code, don't use it. – Some programmer dude May 02 '23 at 11:14
  • 1
    By the way, the code you found and show us, doesn't actually work. It will lead to *undefined behavior* and possibly crashes (or at the very least to some weird and unexpected results). – Some programmer dude May 02 '23 at 11:14
  • _but I do not understand the buffer section._: please clarify. What do you not understand? The `[50]` in `char buffer[50]`? The `&`and/or `[49]` in `ptr = &buffer[49]`? Or...? – Jabberwocky May 02 '23 at 11:16
  • why ptr = buffer[49] and next after that *ptr = '\0' and a the end it egal to hexabase[num/base] – Bat_Under May 02 '23 at 11:18
  • It starts from end because in Arabic numbers we have least significant digit (that we can extract with % base) as rightmost in number. – Öö Tiib May 02 '23 at 11:23
  • 2
    The easiest way to convert an arbitrary integer value into a string is to do it digit by digit. But without knowing how many digits there are in the value, how do we find the first digit to add to the string? The answer is: We *don't*. Instead we begin with the smallest digit, which is very simple and trivial, and work up through the larger digits until there are no more digits. – Some programmer dude May 02 '23 at 11:23
  • [Continued] By doing that with e.g. the value `13`, we get the `3` and add it to the string. Then we take the `1` and add it. That will give us `"31"`. What the code is doing is adding to the string in the opposite direction, so it puts the smallest digit at the end of the string, then put the next smallest before the smallest. That way we don't have to reverse the string, it's kind of automatic.Using this `13` becomes `"13"`. – Some programmer dude May 02 '23 at 11:24
  • But then the current function throws it all away because it returns a pointer to the *local* array `buffer`. The life-time of that array will end when the function returns, and the pointer returned will become invalid. Dereferencing the returned pointer leads to above mentioned undefined behavior. – Some programmer dude May 02 '23 at 11:27
  • 1
    For a better way to understand it yourself, why not use a [*debugger*](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) to step through it line by line while monitoring variables and their values? I recommend you also use pen and paper to keep track of the variables and see how they change. And simplify complex expressions to simpler, using temporary variables. For example instead of `*--ptr = ...` use `char *temp = ptr - 1; *temp = ...; ptr = temp;` – Some programmer dude May 02 '23 at 11:30
  • 1
    At least enable your compiler warnings and read those. I can't find a C++ compiler that does not tell that posted code is defective. – Öö Tiib May 02 '23 at 11:32
  • 3
    This code is not correct. It returns a pointer to some portion of the `buffer` array. But that array is destroyed when the function exits, so you end up with a pointer pointing at invalid memory. Clearly whoever wrote this function did not understand this, despite it being a basic fact of C++. I would throw this function away, and I would not read anything more by the person who wrote this code. It's a good illustration of how 'searching the internet' is not a viable way to learn C++. Please consider buying a book that will teach you this stuff properly. – john May 02 '23 at 11:42
  • there is a much easier way to convert a string base 10 representation of an integer to base 8 or base 16. You should understand why the code you found is wrong, then you might want to open another question to ask about the actual problem you are trying to solve. Why this code uses some buffer is the wrong question, because that code is broken beyond repair – 463035818_is_not_an_ai May 02 '23 at 11:54

1 Answers1

0

Your function is wrong because if returns the pointer to a local variable. This may appear to work under certain circumstances, but as explained in numerous comments this yields undefined behaviour because as soon as the function terminates, the local variables do no longer exist.

*--ptr = foo is the same as ptr = ptr - 1; *ptr = foo.

And this is a corrected version of your function and an example of how to call it.

It is rather C code than C++ code (BTW are you actually programming in C or in C++?) and there may be errors as I haven't properly tested it.

#include <stdio.h>
#include <string.h>

#define BUFFER_LENGTH 50      // define length of buffer in one place,
                              // avoids magic numbers all over the place

char* convert(unsigned int num, int base, char *buffer) {
  static char Representation[] = "0123456789ABCDEF";

  char *ptr = &buffer[BUFFER_LENGTH - 1];  // ptr points at the end of the buffer
  *ptr = '\0';                             // put a null terminator for the string

  while (num != 0) {
    *--ptr = Representation[num % base];   
    num = num / base;
  }
                                           // now ptr points to the beginning of the
                                           // string we want

  memmove(buffer, ptr, strlen(ptr) + 1);   // move the string at the beginning
                                           // of the buffer
  return buffer;
};


int main()
{
  char buffer[BUFFER_LENGTH];   // we provide the buffer so it
                                // still exists once convert has terminated
  puts(convert(0xF1234ABC, 16, buffer));
}

For memmove read it's documentation.

BTW: 50 is too much for BUFFER_LENGTH. As an exercise I le you find out yourself which is the maximum buffer size actually needed.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115