value of type char cannot be assigned to value of type char* ??

D.V.D

Make a wish
Reaction score
73
So I've been getting along my OpenGl tutorial and I came to a problem when writing my texture class. In the class you have a variable that determines the name of the file where the texture is located:

Code:
char* fileName;

I want to set the value to the actual file name in the constructor of the class but I keep getting the error:

"a value of type "char" cannot be assigned to a value of type "char*""

The method call and the actual method look like this:

Code:
Texture (GLenum TextureTarget, const char& FileName);

Code:
Texture::Texture (GLenum TextureTarget, const char& FileName) {
 
    textureTarget = TextureTarget;
    fileName = FileName;
 
}

How do I get around this problem? The whole chars and const char errors have been coming up for me for a while but I can't find a way around them :S
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
You're using a reference instead of a pointer.

char* is not the same as char&.

char* is a pointer to a char or, to a char array (= a string).
char& is a reference to a single char.

So your function should actually say "const char* FileName".

On a side note: What is char& for?

Usually when you pass a variable you implicitely make a copy of it:

Code:
void func(int i){
    i = 5;
}
 
void main(){
    int i = 2;
    func(i);
    //Here i is still 2.
}

Both i's are completely different variables. So setting i in func() will not actually change i in main(). So main's i is copied into func's i.
That's why this way of passing variables to a function is called "pass by copy".

If you use &:

Code:
void func(int& i){
    i = 5;
}
 
void main(){
    int i = 2;
    func(i);
    //Here i is 5.
}

Now we don't pass a copy of i to func, but instead a reference. This means that both i's refer to the same integer! If I change one, then the other one will change too. func's i is a so-called alias to main's i.
(By the way: the variables don't have to have the same name. I just chose it arbitrarily.)
This is called "pass by reference".

What you have accidently done is you wanted to pass a char* but passed a char&.
Notice that these are two complete different types. The first is of type char*, the second one of type char. That's why it's not compatible.
You could make it work by changing it to a char*& (a reference to a char*). This way you could modify FileName from inside Texture().
But that's pretty useless. You shouldn't use the &-operator for variables until you know that you need it. But it's useful to know.

Just for information:
You can also use std::string to pass your file name:

Code:
Texture::Texture (GLenum TextureTarget, const std::string FileName) {
 
    textureTarget = TextureTarget;
    fileName = FileName; //this one should be a std::string too
 
}

The nice part about this is that you don't have to worry about char*, but you can simply always pass std::string. It also makes concatenating a lot easier.

Code:
    std::string file = fileName + ".png"; //This wouldn't work with a char*
 

D.V.D

Make a wish
Reaction score
73
Always with the great explanations :D

Well the reason i passed &char is cause that's what the the tutorial you showed me had in its source code. Of course they used a std::string variable but I had trouble adding their image library into my project so I decided to use a different one that loads a BMP file for me. I had no previous experience with std::string and I did have quite a bit of trouble working with char variables before -.-. Looking at it now, it really doesn't make much sense to have char& variable passed but lots of the source code in http://ogldev.atspace.co.uk/ still use it o_O Isn't it quicker than creating a whole separate space in memory for the variable and safer than using pointers?
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
That's the idea behind it. If you don't make a copy then you don't have to pay the performance cost of copying the object.

Btw &char is not the same as char&. char& is a reference to a char, while &char is invalid syntax.
It's important to remember because &nameOfSomeVariable is valid syntax but means sometimes entirely different.
Oh the joys of C++ ;D

But it's not as easy as that. The copy cost depends on the size and complexity of the object. A char* is very small and is not complex at all, so copying it is just as expensive as passing it via reference.
Same goes for std::string, but for a different reason. It uses rvalue move semantics to prevent unnecessary copying. Same goes for a lot of other classes.
Also, that's kinda of premature optimization. Nowadays computers are so fast that you probably won't ever have to do this kind of performance optimization for your hobby projects. The things are only important for stuff like games which need every little single bit of power it can get.

So in general:
If you see something like int& or std::string& being passed and you do not want to use it to modify the original value (like I described in my post above) then just get rid of the &.

If you see something like &variableName then it has a different meaning. It turns a variable into a pointer to itself ( e.g. int -> int*):
So you sometimes need that one if you want to pass a variable to a function which needs a pointer of some sort.
 

D.V.D

Make a wish
Reaction score
73
Haha I see, when i ran through my old "Learn C++ in 21 Days" they had the explanations of different places of the '*' and '&'. Unfortunately, at the moment I am making a game engine based off a tutorial that later I can modify to fit my hobbies :) Which kinda sucks cause you have to make sure everything is super optimized depending on the detail of your game. You can compare crysis 1 on HIGH settings to crysis 2 on HIGH settings and see the difference in performance on the new engine.

Thats weird, I kinda get what you mean for the std::string variable, but even though char is a small in terms of memory, why would creating a reference/pointer be just as fast as recreating the entire variable itself? Its still less of a operation isn't it? For example, if I ran a function 1000 times and all it did was idk just print some statement passed to it via arguments (char), wouldn't the application finish quicker if the function took the argument as a pointer/refrence even though the char variable has a small memory foot print?

Btw this is a little of topic but I found that the latest GLUT library doesn't seem to have the functions:

glutEndMainLoop();
glutSetOption(some arguments);

Are there new alternatives because the documentation says the variables are still available o_O
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
I'm not very knowledgable about GLUT because I prefer to do things myself, but make sure you're getting the latest freeGLUT, not the normal GLUT. Other than that I don't know.

Regarding the copying of a char*:
It's because of what a pointer actually is. A pointer always only points to a memory address. A memory address is simply an integer number.
As you might know the entire memory that your program can use is numbered, starting from 0 and up to i.dont.know.how.much. These are the addresses.

If your write something like this:
Code:
char* c = "this is a string"; //This is a 17 characters long string

Then your compiler reserves 17 bytes somewhere in memory and writes this string into it, without your doing.
Next it'll give c the value of the address of the start of this 17-byte block. This way c points to this string in memory.

See this image for reference:
http://cdn4.raywenderlich.com/wp-content/uploads/2012/02/C-string-700x309.png
c would point to the letter 'C', and the NUL (0) at the end denotes the end of the string.

So when you do:
Code:
char* c = "this is a string";
char* p = c;

Then you're copying c into p. However c is only a pointer, not the actual string (because this one resides in memory somewhere else).
So you only copy over the memory address which is kept in c.

This actually makes pointers a lot like references, and you have to be wary of that:
Code:
char* c = "this is a string"; //First letter of c is 't'
char* p = c; //c and p now point to the same string
p[0] = 'a'; //We change the first letter in the string of p
 
//Now "this is a string" is actually "ahis is a string".
//That goes for BOTH c and p.

Since you only copy the memory address this means that c and p point to the exact same string. If you change the string through p then it'll also have an effect on c.

Now you can see why passing a char* is very cheap. You only copy over a 4-byte memory address instead of an entire string.
References work the same way interally. Basically a reference is nothing but a pointer in disguise. But the semantics and syntax is a bit different.

As a side note:
It's actually very hard to pass a normal string via copy. If you pass it as char* you'll only copy the pointer and even if you do something like this:

Code:
void func( char array[] ){
    //Do something
}
 
void main(){
    char someString[] = {"some string"}; //We create a real array of characters
 
    func( someString ); //And pass it over
}

Even now the char[] that you pass to func will actually be converted into a char*. It's one of the finer details of C parameter rules.
So you'll have to go out of your way to actually pass a real copy of a string to another function, instead of just it's pointer/reference.

Unless you use std::string. std::string will use the normal pass-by-copy and not pass around pointers to each other. That makes every single string unique, even if they have the same content.
While this indeed means that passing a std::string will make the progam have to copy more memory around we have to remember what we're dealing with.

Memory is fast. Horribly fast. We're talking about mere nanoseconds. Copying 4 bytes for a pointer or 400 bytes for an entire string doesn't make much difference.
And there's a thing much faster than normal memory: Cache.
Cache is used to.. uhmm.. cache parts of main memory into it. Your compiler will try to work as much with your Cache as possible.

Computers are incredibly sophisticates about making things fast.

You say you have to make everything super optimized, but you're not making a Crysis game.
I know this missconception. I thought (and sometimes still think) so myself.
It gets real funny once you start benchmarking and look how stupidly fast everything is.

A few days ago I added support for Wavefront models into my own OpenGL project. And to test it out I loaded a huge model (about 1.4 MB model data) and I thought it'd probably make my fps drop, at least a bit.
Well, it turns out rendering this model took 0.5% of a frame. With over 200 frames per second.
Assuming linear increase I could render 200 of them and still stay at 200+ fps. :D

Optimizing is fun - I do it all the time for fun - but don't think that you HAVE to do it or you'll end up with bad performance.
 

D.V.D

Make a wish
Reaction score
73
Hmm i seem to understand about everything XD. Ill probably read over this a few times to get it to stick in my head! Another side note about cache, the compiler already takes care of using all of the cache in the CPU for me regardless of how much L1, L2, L3 Ln cache there is per core right? And if I use one core, does it only use the cache in one core or does that depend on the x86 systems and all of that complicated stuff? :p ( I was looking at why the XBOX emulator is so hard to write and they were talking about how they have to emulate the x86 system or something like that and all these different internal parts of the XBOX (graphics card and CPU) that I never really knew existed. For me everything in a computer just seemed so simple up until then :p).

Never know maybe one day it will be a crysis game XD Jokes aside, that is a very good point that I never thought about before. I guess Ill start saving optimizing for when its actually needed but there's still lots about that topic that I want to learn about ( octrees, BTree's and all those different ways of representing data ). The thing that always worried me about optimizing is that its very easy to max out your system by exponentially increasing lets say, texture size or polygon count or number of bounces for light rays (if the engine uses them), anti0-alizing samples, etc. Thats why I always thought maybe you'll need to constantly optimize your system just cause for AAA games, we haven't gotten to the point where we can throw away large chunks of memory due to laziness in big games.
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
Yes, your computer will automagically make use of Cache just as it does with RAM. Each core only uses their own cache. Maybe multi-core architectures have some shared cache but that doesn't really matter as you don't have to care about that.

You're right that you can always bring your program to the brink of destruction by simply adding more and more polygons or large textures.

But optimization like using references or pointers (& and *) allow you to squeeze the last bit of performance out of your application.
If your program maxes out at 1,000,000 polygons per frame then you won't magically make it 2,000,000 by just optimizing a few references here and there.

It will be a minor, maybe unnoticable, improvement. And if you screw up you might actually end up making things slower.

What really makes a difference is your design. Using more efficient algorithms may very well double your performance.
Things like octrees, backface culling, efficient sorting, what-not.

However, even there you need to be careful. Even the best octree won't do much if you only have 20 objects in your 3D world. It'll only start to become useful once you meet certain critera.

That's why the general rule of thumb is: Keep it simple and easy. Only when you notice that you NEED more performance you should start changing parts of your code.
If you learn how to write an octree (and the million other awesome things you can use in a AAA game) then you'll never get anywhere.

But 3d applications are very tricky in terms of optimization.
That's because you're working with your CPU and Graphics Card (GPU) seperately!
The CPU runs your program code. It handles logic, sorts your objects, loads files, etc.
The GPU works with your polygon data, it calculates colors, handles textures, etc.

So if you pump 1,000,000 polygons into your program your GPU will have to do a lot of work.
But optimizations like using & and * are code improvements. They won't help your GPU one bit.
So in the end you optimize for absolutely nothing, because the GPU is the limiting factor here.

On the other hand it's very hard to judge how much work your GPU is doing.
If you tell your GPU to draw 1,000 polygons you might measure that it takes 2ms to draw it.

If you draw 2,000 you would expect it to take 4ms instead.
But often times that's not the case. It might only take 3ms, or maybe also 2ms. Hell, you might even encounter cases where it would take less than 2ms!

That's because the GPU is a devilish clever piece of magic. It's even better at making things fast than your CPU is. The GPU/driver developers would kill their own mothers to get another fps.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top