can anyone explain const char*, char, strings, char array

Started by
39 comments, last by JohnnyCode 8 years, 6 months ago

I'm sorely confused.

My compiler keeps telling me this function's argument only accepts "cons char*". I gave it a char, a string, a char array, a function that return a char. I really don't know what I'm dealing with. Can anyone explain what I have to give this function and compare and contrast these 3 things.

Advertisement

char is a single character, like 'a', 'B' or '1'. Can internally be any of 256 values (on most platforms where it is 8 bits, some exotic ones use another bit-count).

char[10] is an array of 10 characters stored sequentially in memory.

char* is a pointer which holds the address in memory of a character, for example it can point at a single 'char' variable, or it can point at the address where a sequential array begins.

const char* is such a pointer that is declared constant, which means that any function accepting it promises not to change the values stored in memory at that address. Read-only access to a string is usually the meaning.

std::string is a class that internally holds a memory-buffer of many characters, and has methods to manipulate them.

For string-functions that take const char* it is usually appropriate to pass them string.c_str(), as the c_str() method returns a pointer to an address in memory where the string characters are stored sequentially, + it guarantees to end that sequence with a null-character, which means that a 'char' with value 0 will be stored at the end of the sequence. Such a null-terminator is used by many string functions to determine where a string ends.

General beginner rule: Store your strings in std::string. When you need to pass a function const char*, use the .c_str() function.

That'd cover 99% of what you are likely to encounter, unless you are dealing with unicode stuff.
For the other 1%, where the function is expecting char* and forgot to const-qualify it, you'll have to vomit up a const_cast.

const char* is not a char. const char* is not a string. const char* is not a char array. That's why the compiler complained.

Note the asterisk! That means it's a pointer. A single char is not a pointer, so char != const char*
An std::string is a class, not a char, and not a char*. However, std::string has a function called .c_str() that can convert the string to a const char (no conversion actually happens, but that's an implementation detail, not an interface promise).

A char array is also not a char pointer, but by taking the address of the first element of the array, you can convert it to a char pointer.


const char *ptr = &myArray[0];

There are risks with this though, because the function is making assumptions about the length of 'ptr', either by you passing in the character count, or by it being ended by a null char, or (sometimes) it being ended by two null chars in a row. So unless you really truly know what the function is expecting, and what your array contains, it's best to play it safe.

Thanks, I think I get it now. Even if it's pointing to a char it's still a pointer. I was wrong to make the assumption it would accept. This was a big help toward my main goal. Again thanks.


char* is a pointer which holds the address in memory of a character, for example it can point at a single 'char' variable, or it can point at the address where a sequential array begins.

const char* is such a pointer that is declared constant, which means that any function accepting it promises not to change the values stored in memory at that address. Read-only access to a string is usually the meaning..


const char*

Is not a constant pointer its actually a pointer to a constant char.


char* const

Would have been a constant pointer to a char. There is a difference in this stuff so be careful learn when the pointer is constant and when the actual object the pointer is pointing at is constant.


const char* const

Would be a constant pointer to a constant char.

The difference between the first two is subtle but effectively it means I can assign a new address to the variable that is decalred that way as long as the memory it points at is of const char type, I cannot change the value in the memory location of the pointer. In the second example I can not change the address of the pointer, however I can change the value in the memory location of the pointer. In the last case you cannot either of the two operations above.


char aChar = 'a';
const char* pointerToAConstantChar = &aChar;
char* const constantPointerToAChar = &aChar;
const char* const constantPointerToAConstantChar = &aChar;

char bChar = 'b';

*pointerToAConstantChar = 'B'; //Error: cannot change the value in aChar
pointerToAConstantChar = &bChar;

*constantPointerToAChar = 'B';
constantPointerToAChar = &bChar; //Error: cannot change the pointer

*constantPointerToAConstantChar = 'B'; //Error: cannot change the value in aChar
constantPointerToAConstantChar = &bChar; //Error: cannot change the pointer

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

As a side note.

const is a good subject to explore and I believe you should get into the habit of making your code const aware, part of this is const functions in a class

In the following the function CalcSomeValue is tagged const, which means that it does not change the state of MyClass, it is a read only function. Been a while since I worked in C++ but I believe this is compiler checked.

The effect of this is that if you have a const MyCLass* you are only able to call const functions on the object as you have a const object.


class MyClass
{
public:
	int CalcSomeValue() const
	{
		// code that returns something
	}
};

Cost in C++, unlike C# and some other languages, is a subtle keyword that is worth learning. It provides lots of semantic implications in function contracts that you need to understand as you pull in 3rd party libraries etc as you will encounter it a lot :)


For the other 1%, where the function is expecting char* and forgot to const-qualify it, you'll have to vomit up a const_cast.

I only ever had to use const_cast, when I used some badly designed or outdated libraries (looking at you, FreeImage!). I think replacing the library, or if it is your own code, fixing it, is the right answer. Beginners should not even be told about const_cast in my opinion, it'll just cause trouble somewhere down the road.

If I'm forced to pass a char* due to a badly designed library, I prefer to do this than fall back on a const_cast, unless there is a good reason to avoid the additional overhead:

void badMethod(char *s);

void f(const char *s)
{
    std::vector<char> v(s, s + strlen(s) + 1); // +1 to ensure the null terminator is added
    badMethod(v.data());
}
const_cast is undefined behaviour if it is invoked on an entity that was originally declared as const, since the compiler may have decided to locate it in read-only memory.

I only ever had to use const_cast, when I used some badly designed or outdated libraries (looking at you, FreeImage!).


That's what I'm talking about: the 1% is badly designed/outdated libraries. Unfortunately, I think one of the improperly non-const char* functions is inherited from the C standard library, though I can't remember what function.

I think replacing the library, or if it is your own code, fixing it, is the right answer. Beginners should not even be told about const_cast in my opinion, it'll just cause trouble somewhere down the road.

Absolutely!

If I'm forced to pass a char* due to a badly designed library, I prefer to do this than fall back on a const_cast, unless there is a good reason to avoid the additional overhead:


void badMethod(char *s);

void f(const char *s)
{
    std::vector<char> v(s, s + strlen(s) + 1); // +1 to ensure the null terminator is added
    badMethod(v.data());
}
const_cast is undefined behaviour if it is invoked on an entity that was originally declared as const, since the compiler may have decided to locate it in read-only memory.

Wouldn't this work?


void badMethod(char *s);

void f(const char *s) // but likely the parameter will have to leave out const in its declaration, to not be a corrupted declaration?
{
    char* memofstr=s; 
    badMethod(memofstr);
}

I understand only that const at defintion makes compiler to warn/error you out if the variable is left-side placed, or promises to not alter if something is declared as const (public parameter for example)

This topic is closed to new replies.

Advertisement