2

I'm trying to make a name generator that uses preset syllables accessed from three different arrays.

#include "main.hpp"

Namegen::Namegen() {
}

const char *Namegen::getFirst() {
    const char *name;
    int rNum = rng->getInt(0, 5);
    const char *firstSyllable = start[rNum];
    rNum = rng->getInt(0, 5);
    const char *secondSyllable = mid[rNum];
    rNum = rng->getInt(0, 5);
    const char *lastSyllable = end[rNum];

    name = firstSyllable + *secondSyllable + *lastSyllable;

    return name;
}

There are a total of 6 syllables in each array, so I have the min set to 0, and the max to 5. Six numbers in total. Yet, for some reason, it looks like it's generating an 8 somewhere? I'm not entirely sure what the exception is talking about, but hopefully someone else does. This is the exception (even though it's in the title already):

0xC0000005: Access violation reading location 0x0000000000000008.

This is my Namegen.hpp file (linked through the main.hpp file):

#pragma once

class Namegen {
public:
    const char *start[6] = { "Ba", "Ce", "Ti", "Mo", "Lu", "Dy" };
    const char *mid[6] = { "ma", "te", "di", "so", "ku", "ly" };
    const char *end[6] = { "ban", "can", "dan", "fan", "gan", "han" };

    Namegen();
    TCODRandom *rng;
    const char *getFirst();
};

Why is it throwing this exception, and how do I fix it?

I got it to the point that I can successfully concatenate the values, using the following code:

std::string Namegen::getName() {
    int r = rng->getInt(0, 2);
    std::string firstSyll = fSyll[r];
    r = rng->getInt(0, 2);
    std::string midSyll = mSyll[r];
    r = rng->getInt(0, 2);
    std::string lastSyll = lSyll[r];

    std::string name = std::string(firstSyll) + std::string(midSyll) + std::string(lastSyll);

    return name;
}

However, it now throws this exception:

Exception thrown at 0x00007FF978AD9E7A (ucrtbased.dll) in AotDK.exe: 0xC0000005: Access violation reading location 0x0000000000000000.
  • You cannot assign value to `const` variables. You can only initialize them (I'm kinda surprised it compiled). Since you don't initialize `name`, it's some random rubbish pointer. You then try to write to that location, which is Undefined Behaviour. – Yksisarvinen Jun 08 '18 at 06:59
  • 2
    What did you expect `name = firstSyllable + *secondSyllable + *lastSyllable;` to do? – Algirdas Preidžius Jun 08 '18 at 06:59
  • 3
    You can probably consider using `std::string` and a STL container such as `std::vector`. Also, look into how you are concatenating the portion of names. – Vishaal Shankar Jun 08 '18 at 07:00
  • @Yksisarvinen No, OP doesn't try to write to the location pointed to, by `name`. He assigns said memory location, without dereferencing it. – Algirdas Preidžius Jun 08 '18 at 07:00
  • I'm coming over to C++ from C#, so please forgive my ignorance. I wanted it to concatenate the values and create a name, but it looks like I was horrendously misjudging the usage of the + operator when referencing this sort of thing. – Jacob McNamara Jun 08 '18 at 07:03
  • 3
    @JacobMcNamara Then, you should learn C++ from a [good C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). Learning C++ by guessing is **not** the way to go. – Algirdas Preidžius Jun 08 '18 at 07:09

1 Answers1

6

name = firstSyllable + *secondSyllable + *lastSyllable; is nowhere near a concatenation. (The compiler compiles it as it thinks you're doing some pointer arithmetic on firstSyllable.) The behaviour is actually undefined as you are assigning something that isn't nullptr or the address of an object to name.

Ditch all the char* stuff, and use std::string instead. Then + will act as a concatenation as it's an overloaded operator in the string class.

Your data would then take the form

std::vector<std::string> start = { "Ba", "Ce", "Ti", "Mo", "Lu", "Dy" };

which demonstrates the power of the C++ standard library. You need to #include <string> and #include <vector> to bring in that functionality.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • I'm getting the following: namespace "std" has no member "string". – Jacob McNamara Jun 08 '18 at 07:08
  • 1
    @JacobMcNamara `#include `? – Algirdas Preidžius Jun 08 '18 at 07:09
  • 4
    @JacobMcNamara: See next comment up and the amendments to the answer. By the way, C++ is not a shallow learning curve! Really you need a good book. Stroustrup is my favourite, by far. And I'd set three months aside and read K & R first; completing all the example exercises. – Bathsheba Jun 08 '18 at 07:10
  • I've got that much working now, however it comes down to it that the library I'm using to make this game doesn't use std::string it turns out. I won't be able to use std::string for this purpose without going through and recoding the library. Is there any other way to do this? – Jacob McNamara Jun 08 '18 at 07:20
  • 1
    You can do all the string manipulation using std::string, then call the c_str() method if you need (read-only) access to the character buffer. – Bathsheba Jun 08 '18 at 07:21
  • @Bathsheba I'm having a bit of trouble understanding how to use c_str in this context. Do you want me to c_str() the firstSyllable, mid...etc. or the std::string name? – Jacob McNamara Jun 08 '18 at 07:31
  • 3
    @JacobMcNamara: That depends on what the function that you're attempting to call that expects a `const char*` is. Really now is the time for you to down tools and start reading. – Bathsheba Jun 08 '18 at 07:32
  • @JacobMcNamara : To add to Bathsehba's answer, initialize the `start`, `mid` and `end` part of the member-initializer list instead of the way you do it in the question. If you are not aware of this, then a good book will certainly let you in on that info. – Vishaal Shankar Jun 08 '18 at 07:35
  • @VishaalShankar Looks like I need a book, then. I do most of my learning on Lynda.com right now, is that a good source? – Jacob McNamara Jun 08 '18 at 07:41
  • @JacobMcNamara. No it isn't. Apologies in advance for the dogma, but read K & R first (and do the exercises), then Stroustrup. – Bathsheba Jun 08 '18 at 07:48
  • Wait, I just realized I could overload the function giving me the error so that there's an overload that doesn't interfere with the rest of the library. I don't know why I didn't see this before, I'll let you know if it works. – Jacob McNamara Jun 08 '18 at 07:59
  • Okay, I got it to compile with this code: `#include "main.hpp" Namegen::Namegen() { } std::string Namegen::getFirst() { std::string name; int rNum = rng->getInt(0, 5); std::string firstSyllable = start[rNum]; rNum = rng->getInt(0, 5); std::string secondSyllable = mid[rNum]; rNum = rng->getInt(0, 5); std::string lastSyllable = end[rNum]; name = firstSyllable + secondSyllable + lastSyllable; return name; }` but it's still giving me that 0x00000000000008 exception. Edit: Wow, that looks horrendous in a comment. Should I update my question so it's easier to read? – Jacob McNamara Jun 08 '18 at 08:10
  • I like your answers in general Bathsheba because they explain the problem and suggest a solution very concisely. – YSC Jun 08 '18 at 08:29
  • @JacobMcNamara check you're _actually_ compiling and run the _actual_ new program. – YSC Jun 08 '18 at 08:29
  • @YSC That's very kind of you to say so! – Bathsheba Jun 08 '18 at 09:02
  • @Bathsheba I got it to the point that it's throwing an exception in a different spot now, if that makes any difference. Check my question above for the details (I will update it here in a sec) – Jacob McNamara Jun 08 '18 at 14:01
  • Nevermind, I know what the issue is now. Part of the code in this library is using strcat_s on the value of the name, but when I overloaded the function that uses this value so I could use std::string, I made it that calling on actor->name returned NULL. Nice one, me. Maybe I should hang this one up and settle for a Markov chain... – Jacob McNamara Jun 08 '18 at 14:20