Jump to content

C++ How does this piece of code work(pointers and char arrays)?

¨TrisT¨
Go to solution Solved by Pinguinsan,

Consider the following:

A pointer is a variable (usually one byte in size) that "points" to another place in memory. What the variable points to can be very large, very small, it doesn't matter. In C++, when you declare a "normal" variable, it makes space for the size of the object  assigns it whatever value you give it:
 

int i = 15;

the variable i is of type "int", and is equal to a value of 15. Cool. Now, you declare a pointer variable:
 

int *myPtr;

The great confusion of this syntax is that the "*" operator can either be a multiplication operator, or a dereference operator (more on that in a minute). But in this case, it is neither. The above line of code declares a variable myPtr of type "pointer to an int", and it is not initialized (it is currently referred to as a null pointer). So, we want to do something useful with it. So, we can "point" the pointer variable to the first variable "i" like this:
 

myPtr = &i;

The "&"operator, when placed before a variable, means "take the address of this variable". Recall from before that the variable i has an address in memory, and a value associated with it. We have set myPtr to point to the address of i. This then allows us to use a dereference operation to get the variable:
 

*myPtr = 20; //i now equals 20, NOT 15

As mentioned before, "*" is a dereference operator, when appearing before a pointer variable. As such, these two lines are now equivalent:
 

i = 25;
*myInt = 25;

Both set the variable "i" to now equal 25! Further, you cannot directly assign to a pointer, but you can add or subtract from it (more on that later). So this is a syntax error:
 

myInt = 50; //ERROR! myInt is of type pointer, and cannot be assigned to a number



Okay, so that's all well and good, but how does that make "const char *" a string of characters? Well, it may be helpful to talk about arrays. Arrays in C++ are really just pointers in disguise. These two lines of code are the same:
 

const char *myChar = "Hello";
const char myChar[] = "Hello";

The easy question to answer is: where did const come from? The const keyword in C++ is absolutely wonderful. It allows variables to be declared that cannot be modified after they are assigned. As such, strings of characters are constant in memory. The compiler will store those strings somewhere in memory, and never change them. Don't worry about why for now, just accept that strings are not changeable as const char * variables. Single characters are in single quotes in C++, where strings are in double quotes. Also, the syntax myChar[0] would mean the first character in the myChar array. Okay, so now we look at the second example and exactly what the array contains:

myChar[0] = 'H'
myChar[1] = 'e'
myChar[2] = 'l'
myChar[3] = 'l'
myChar[4] = 'o'
myChar[5] = '\0'

Whoa, so what is that '\0' character at the end? Well, the forward slash is called an escape character, and it just means "treat whatever comes after this as something special". The '\0' character is especially special, as it is called the "null" character. It doesn't actually mean character code 0, it means "this is the end, period." So, when a computer reads through the character array of myChar, it gets to the null character and says "okay, this is the end of the string".

To bring it all together, recall that variable "myChar" is of type pointer to const char. The last trick up our sleeves is to know that you can add or subtract to pointers (as mentioned above). What does this do? Well, pretend myChar is pointing to an address of your house on your street. myChar+1 would then point to an address of your neighbor! Further, myChar-1 would point to an address of your other neighbor. And before we go all the way, note that this is a very easy way to crash programs: If you try to use the dereference operator on a pointer to a place in memory it does not own, the program will crash (called undefined behavior), and your operating system will tell you there was a "segmentation fault". This makes sense, as you don't want a program to be able to access any memory it darn well pleases, especially if that other memory has sensitive information in it. Okay, so now the above: the syntax [0], [1], ... is equivalent to this:
 

*(myChar+0) = 'H'
*(myChar+1) = 'e'
*(myChar+2) = 'l'
*(myChar+3) = 'l'
*(myChar+4) = 'o'
*(myChar+5) = '\0'

So each line adds to the myChar pointer (taking the address of a neighbor) before dereferencing it. So in memory, the computer has the string "Hello\0", and you are just taking the address of them one by one! Since the variable myChar was declared with an entire string constant (myChar = "Hello";), the operating system knows that your program owns all of that memory, as long as you don't try to actually use the 6th line (myChar + 5), because we now know that myChar+5 points to a null character.

Sorry if some thing doesn't make sense, but that's a (very) basic overview of pointers.

TLDR: The & symbol is an "address of" operator, and the * symbol is either a "I'm declaring this as a pointer" or a "dereference this pointer" operator.

Hi!

I'm starting to learn c++ because it is a language I respect very much.

I knew this was gonna be hard because I came from web development and c#.

I can get things done by grabbing pieces of code from here and there and throwing it all in a blender but that's not what I want to do.

I've read that it's best to use char arrays instead of strings in almost any case where you don't need to make any alterations to the content itself.

But since I started I keep seeing these apparently random asterisks and ampersands all over the place, and I went around reading.

I'm having a really hard time understanding the concept of pointers and the more I read the more confused I get.

 

This code:

   time_t now = time(0);
   char* dt = ctime(&now);
   cout << "The local date and time is: " << dt << endl;
   tm *gmtm = gmtime(&now);
   dt = asctime(gmtm);
   cout << "The UTC date and time is:"<< dt << endl;

First off why does the * make a char variable a char array variable?

Then what does the & before the now mean? What does it do? Apparently if I take it off I get an invalid conversion from time_t to const time_t*

   Well now I'm even more confused, what the hell does that * do after const time_t? And what the hell does a constant have to do with any of this?

Fourth line, I don't get the functionality of that * before the variable name, but it's gotta be something completely different from char* right?

   And ofc, there is the & again.

 

I would really appreciate some help with this because I'm overwhelmed and way over my head.

 

Thank you!

Link to comment
Share on other sites

Link to post
Share on other sites

https://recordings.engineering.illinois.edu:8443/ess/echo/presentation/786ba6c3-3bc8-4554-902f-9db9a725a5ea

 

This should help a bit (starting around 30 minutes in). I think you should be able to see that without being logged in....unless incognito is acting screwy. 

 

A bunch of other lectures from my (C++) data structures class that I took a couple years ago (although, these are the lectures from this year): https://chara.cs.illinois.edu/cs225/lectures/

PSU Tier List | CoC

Gaming Build | FreeNAS Server

Spoiler

i5-4690k || Seidon 240m || GTX780 ACX || MSI Z97s SLI Plus || 8GB 2400mhz || 250GB 840 Evo || 1TB WD Blue || H440 (Black/Blue) || Windows 10 Pro || Dell P2414H & BenQ XL2411Z || Ducky Shine Mini || Logitech G502 Proteus Core

Spoiler

FreeNAS 9.3 - Stable || Xeon E3 1230v2 || Supermicro X9SCM-F || 32GB Crucial ECC DDR3 || 3x4TB WD Red (JBOD) || SYBA SI-PEX40064 sata controller || Corsair CX500m || NZXT Source 210.

Link to comment
Share on other sites

Link to post
Share on other sites

12 minutes ago, djdwosk97 said:

https://recordings.engineering.illinois.edu:8443/ess/echo/presentation/786ba6c3-3bc8-4554-902f-9db9a725a5ea

 

This should help a bit (starting around 30 minutes in). I think you should be able to see that without being logged in....unless incognito is acting screwy. 

 

A bunch of other lectures from my data structures class that I took a couple years ago (although, these are the lectures from this year): https://chara.cs.illinois.edu/cs225/lectures/

Thank you! I'm downloading everything :D

Can I? I don't want to get anyone in trouble.

Link to comment
Share on other sites

Link to post
Share on other sites

Just now, ¨TrisT¨ said:

Thank you! I'm downloading everything :D

Can I? I don't want to get anyone in trouble.

I don't see how you could possibly get in trouble. It's not like you need an account to open the page. 

PSU Tier List | CoC

Gaming Build | FreeNAS Server

Spoiler

i5-4690k || Seidon 240m || GTX780 ACX || MSI Z97s SLI Plus || 8GB 2400mhz || 250GB 840 Evo || 1TB WD Blue || H440 (Black/Blue) || Windows 10 Pro || Dell P2414H & BenQ XL2411Z || Ducky Shine Mini || Logitech G502 Proteus Core

Spoiler

FreeNAS 9.3 - Stable || Xeon E3 1230v2 || Supermicro X9SCM-F || 32GB Crucial ECC DDR3 || 3x4TB WD Red (JBOD) || SYBA SI-PEX40064 sata controller || Corsair CX500m || NZXT Source 210.

Link to comment
Share on other sites

Link to post
Share on other sites

char* dt

This is a pointer that points to a reference of type char
 

&now

This is creating a reference to the memory location for a pointer to point to, I can only assume that the function it is inside of also outputs as a char*.

 

tm *gmtm

This is the exact as as "char* dt" as the compiler does not care where the * is placed in this case, only that the * is there.

CPU - Ryzen 7 3700X | RAM - 64 GB DDR4 3200MHz | GPU - Nvidia GTX 1660 ti | MOBO -  MSI B550 Gaming Plus

Link to comment
Share on other sites

Link to post
Share on other sites

Consider the following:

A pointer is a variable (usually one byte in size) that "points" to another place in memory. What the variable points to can be very large, very small, it doesn't matter. In C++, when you declare a "normal" variable, it makes space for the size of the object  assigns it whatever value you give it:
 

int i = 15;

the variable i is of type "int", and is equal to a value of 15. Cool. Now, you declare a pointer variable:
 

int *myPtr;

The great confusion of this syntax is that the "*" operator can either be a multiplication operator, or a dereference operator (more on that in a minute). But in this case, it is neither. The above line of code declares a variable myPtr of type "pointer to an int", and it is not initialized (it is currently referred to as a null pointer). So, we want to do something useful with it. So, we can "point" the pointer variable to the first variable "i" like this:
 

myPtr = &i;

The "&"operator, when placed before a variable, means "take the address of this variable". Recall from before that the variable i has an address in memory, and a value associated with it. We have set myPtr to point to the address of i. This then allows us to use a dereference operation to get the variable:
 

*myPtr = 20; //i now equals 20, NOT 15

As mentioned before, "*" is a dereference operator, when appearing before a pointer variable. As such, these two lines are now equivalent:
 

i = 25;
*myInt = 25;

Both set the variable "i" to now equal 25! Further, you cannot directly assign to a pointer, but you can add or subtract from it (more on that later). So this is a syntax error:
 

myInt = 50; //ERROR! myInt is of type pointer, and cannot be assigned to a number



Okay, so that's all well and good, but how does that make "const char *" a string of characters? Well, it may be helpful to talk about arrays. Arrays in C++ are really just pointers in disguise. These two lines of code are the same:
 

const char *myChar = "Hello";
const char myChar[] = "Hello";

The easy question to answer is: where did const come from? The const keyword in C++ is absolutely wonderful. It allows variables to be declared that cannot be modified after they are assigned. As such, strings of characters are constant in memory. The compiler will store those strings somewhere in memory, and never change them. Don't worry about why for now, just accept that strings are not changeable as const char * variables. Single characters are in single quotes in C++, where strings are in double quotes. Also, the syntax myChar[0] would mean the first character in the myChar array. Okay, so now we look at the second example and exactly what the array contains:

myChar[0] = 'H'
myChar[1] = 'e'
myChar[2] = 'l'
myChar[3] = 'l'
myChar[4] = 'o'
myChar[5] = '\0'

Whoa, so what is that '\0' character at the end? Well, the forward slash is called an escape character, and it just means "treat whatever comes after this as something special". The '\0' character is especially special, as it is called the "null" character. It doesn't actually mean character code 0, it means "this is the end, period." So, when a computer reads through the character array of myChar, it gets to the null character and says "okay, this is the end of the string".

To bring it all together, recall that variable "myChar" is of type pointer to const char. The last trick up our sleeves is to know that you can add or subtract to pointers (as mentioned above). What does this do? Well, pretend myChar is pointing to an address of your house on your street. myChar+1 would then point to an address of your neighbor! Further, myChar-1 would point to an address of your other neighbor. And before we go all the way, note that this is a very easy way to crash programs: If you try to use the dereference operator on a pointer to a place in memory it does not own, the program will crash (called undefined behavior), and your operating system will tell you there was a "segmentation fault". This makes sense, as you don't want a program to be able to access any memory it darn well pleases, especially if that other memory has sensitive information in it. Okay, so now the above: the syntax [0], [1], ... is equivalent to this:
 

*(myChar+0) = 'H'
*(myChar+1) = 'e'
*(myChar+2) = 'l'
*(myChar+3) = 'l'
*(myChar+4) = 'o'
*(myChar+5) = '\0'

So each line adds to the myChar pointer (taking the address of a neighbor) before dereferencing it. So in memory, the computer has the string "Hello\0", and you are just taking the address of them one by one! Since the variable myChar was declared with an entire string constant (myChar = "Hello";), the operating system knows that your program owns all of that memory, as long as you don't try to actually use the 6th line (myChar + 5), because we now know that myChar+5 points to a null character.

Sorry if some thing doesn't make sense, but that's a (very) basic overview of pointers.

TLDR: The & symbol is an "address of" operator, and the * symbol is either a "I'm declaring this as a pointer" or a "dereference this pointer" operator.

Link to comment
Share on other sites

Link to post
Share on other sites

14 hours ago, Pinguinsan said:

These two lines of code are the same:

 


const char *myChar = "Hello";
const char myChar[] = "Hello";

 

They're not.

The first is a pointer, pointing to a string literal "Hello". The pointer itself is mutable.

The second is a char array, initialized with the content "Hello". It decays into a pointer but is immutable:

const char *myChar1 = "Hello";
const char myChar2[] = "Hello";

char c = 'a';
myChar1 = &c;  //OK!
myChar2 = &c;  //error!

//also...
sizeof(myChar1) == sizeof(void*)
  
//while...
sizeof(myChar2) == 6

On many machines with Harvard architecture this can have the side-effect that while the string "Hello" itself might be put in ROM or flash memory, there will still be a pointer created in RAM for "myChar1". For large projects with lots of these string literals this can end up using a lot of RAM needlessly.

Link to comment
Share on other sites

Link to post
Share on other sites

18 hours ago, ¨TrisT¨ said:

This code:


   time_t now = time(0);
   char* dt = ctime(&now);
   cout << "The local date and time is: " << dt << endl;
   tm *gmtm = gmtime(&now);
   dt = asctime(gmtm);
   cout << "The UTC date and time is:"<< dt << endl;

First off why does the * make a char variable a char array variable?

It does not. It makes it a pointer. In C, a string is nothing more then a row of char's. The char pointer points to the beginning of the string and a 0 (not '0') indicates the end of the string.

 

 

18 hours ago, ¨TrisT¨ said:

Then what does the & before the now mean? What does it do? Apparently if I take it off I get an invalid conversion from time_t to const time_t*

 

It takes the memory address of "now" because the function expects a time_t pointer.

"now" is the actual element , of type time_t.

"&now" is the memory address of "now", of type time_t*.

18 hours ago, ¨TrisT¨ said:

   Well now I'm even more confused, what the hell does that * do after const time_t? And what the hell does a constant have to do with any of this?

It means the function expects a time_t pointer like explained above. The "const" means the function promises not to modify the data inside the time_t structure you hand it a pointer to. (Simply put, the function promises not to change the contents of "now").

 

18 hours ago, ¨TrisT¨ said:

Fourth line, I don't get the functionality of that * before the variable name, but it's gotta be something completely different from char* right?

   And ofc, there is the & again.

It's the same as the char* thing. It means "gmtm" is a pointer.

Link to comment
Share on other sites

Link to post
Share on other sites

Thank you everyone, I'm sorry I read this so late, I really have no excuse, I was just being a lazy ahole.

 

On 9/16/2016 at 3:07 PM, Unimportant said:

They're not.

The first is a pointer, pointing to a string literal "Hello". The pointer itself is mutable.

The second is a char array, initialized with the content "Hello". It decays into a pointer but is immutable:


const char *myChar1 = "Hello";
const char myChar2[] = "Hello";

char c = 'a';
myChar1 = &c;  //OK!
myChar2 = &c;  //error!

//also...
sizeof(myChar1) == sizeof(void*)
  
//while...
sizeof(myChar2) == 6

On many machines with Harvard architecture this can have the side-effect that while the string "Hello" itself might be put in ROM or flash memory, there will still be a pointer created in RAM for "myChar1". For large projects with lots of these string literals this can end up using a lot of RAM needlessly.

What does mutable and immutable mean in this situation?

And how does it decay into a pointer? I've read that in quite a lot of places and I can't seem to understand it, the very definition of decay is "the state or process of rotting or decomposition", how does that happen programmatically?

Link to comment
Share on other sites

Link to post
Share on other sites

1 minute ago, ¨TrisT¨ said:

Thank you everyone, I'm sorry I read this so late, I really have no excuse, I was just being a lazy ahole.

 

What does mutable and immutable mean in this situation?

And how does it decay into a pointer? I've read that in quite a lot of places and I can't seem to understand it, the very definition of decay is "the state or process of rotting or decomposition", how does that happen programmatically?

"mutable" and "immutable" in the context of this type of programming refers to whether it can be changed or not. To "mutate" something is to change it. So all const declared variables are immutable by definition: they cannot be changed:
 

const int myInt = 5;
myInt = 10; //ERROR! myInt is declared const, and thus immutable

When he mentions that it "decays into a pointer", it's important to note that the terminology can get sticky in the context of C++. Technically, C++ has a standard library feature called std::decay, but it is way above the scope of this conversation. The basic idea of something "decaying into a pointer" is that something is implicitly converted to something else. The very basic example is of declaring a pointer to an already existing array.
 

int myInts[5] = {0, 5, 3, 4, 6}; //Declare an integer array of 5 elements
int *intPtr = myInts; //Here is where the decay happens. myInts is the exact same as &myInts[0]

The basic idea here is that when you use an array without any brackets (ie myInts[3]), it "decays" into a pointer to the first element in the array. So as the comment mentiones, myInts[0] accessed the first element, and &myInts[0] takes the address of the first element. As said before, using myInts without any brackets returns a pointer to the first element. Therefore, myInts is the same as writing &myInts[0].

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×