Reputation: 5795
I was recently given this bit of code to analyze as a homework assignment (by recently I mean about a 3 weeks ago). We were supposed to go through the code line by line and determine the print statements (without compiling/running).
I get about half way through it and then the pointers start manipulating an array of ints and I just can't keep track of it anymore. Can anyone help explain what values are being manipulated and why?
I imagine that this bit of code and a good explanation would be huge help to not only me, but other people who come from languages that don't have pointers.
Here is the code (note that the comments are my own, and not the instructor's):
int main() {
// Pointers (* var_name) point to an address in memory. They can be
// dereferenced by using (* var_name) during assignment. The operator (&)
// gives the address in memory of a variable, which is useful for assigning
// pointers to (point) to that location in memory (a type of assignment).
int i = 50, j = 100;
int k[] = {10, 20, 30, 40, 50};
// Declare a pointer to p, and a pointer to q
int *p, *q;
// Declare a pointer to a pointer s
int **s;
// Declare a pointer to a pointer to a pointer t
int ***t;
// Since p points to an address in memory, and & gives the address in memory,
// assign p to be the same memory location as i
p = &i;
printf("%d %d\n", i, *p);
// Since q points to an address in memory, and & gives the address in memory,
// assign q to be the same memory location as j
q = &j;
printf("%d %d\n", j, *q);
// Since s points to a pointer to an address in memory, and & gives the address
// in memory, assign s to be the same memory location as p
s = &p;
printf("%d %d\n", *p, **s);
// Since t points to a pointer to a pointer to an address in memory, and & gives
// the address in memory, assign t to be the same memory location as s. Since s
// points to the same location as p, t now points to the same location as t.
t = &s;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
// The pointer p now has the same reference (in memory) as the pointer q
p = q;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
// Since s points to a pointer to an address in memory, and & gives the address
// in memory, assign s to be the same memory location as q. Since p and q point
// to the same location, an equivalent statement is (s = &p)
s = &q;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
/*
* This is where I get seriously lost, and I really have no clue.
*/
// p now points to the first element of k, because the first element of k is
// equivalent to *k (they are both pointers)
p = k;
*p = *q;
p++;
s = &p;
**s = 500;
q = p + 2;
*q = 1000;
p = q - 1;
*p = 750;
q ++;
*q = *q * 100;
printf("%d %d %d %d %d\n", k[0], k[1], k[2], k[3], k[4]);
**s = -100;
***t = -200;
printf("%d %d %d %d %d\n", k[0], k[1], k[2], k[3], k[4]);
printf("%d %d %d %d %d %d\n", i, j, *p, *q, **s, ***t);
return 0;
}
When compiled and run, it gives the following output (for reference):
50 50
100 100
50 50
50 100 50 50
100 100 100 100
100 100 100 100
100 500 750 1000 5000
100 500 -200 1000 5000
50 100 -200 5000 -200 -200
So I'm wondering, what starts happening in the giant block of about 10 manipulations? I can't follow it. Also, please let me know if my comments in the code were wrong, that's just my understanding of it.
PS - I know that the statement p = k
assigns the pointer p
to point to the first element of the int[] k
, but I don't know what happens from that point on concerning k
...
Upvotes: 1
Views: 228
Reputation: 1159
So, let's get this step by step. I will only show you memory operations and let you find out what is being printed. Above each memory location (boxes) is its respective address and inside is its content.
Please note that the memory addresses above the variables are indicative. There is no guarantee that the variables will be placed in the stack that way (most likely they won't).
int *p, *q;
Here you don't declare "pointer to p
or q
", but 2 pointers to int
, called p
and q
.
int **s;
int ***t;
Same, a pointer to a pointer to int
called s
, and a pointer to a pointer to a pointer to int
called t
.
So let's 'draw' the memory so far.
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |
+------+ +------+
k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C
+------+ +------+------+------+------+------+
|0x100C|---->| 10 | 20 | 30 | 40 | 50 |
+------+ +------+------+------+------+------+
p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C
+------+ +------+ +------+ +------+
|XXXXXX| |XXXXXX| |XXXXXX| |XXXXXX|
+------+ +------+ +------+ +------+
Now, let's get the code running:
p = &i;
Now p
points to i
:
i: 0x1000 j: 0x1004
+------+ +------+
+-->| 50 | | 100 |
| +------+ +------+
|
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C
| +------+ +------+------+------+------+------+
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 |
| +------+ +------+------+------+------+------+
|
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C
| +------+ +------+ +------+ +------+
+---|0x1000| |XXXXXX| |XXXXXX| |XXXXXX|
+------+ +------+ +------+ +------+
The next command is:
q = &j;
Now q
points to j
:
i: 0x1000 j: 0x1004
+------+ +------+
+-->| 50 | | 100 |<------------------------------------+
| +------+ +------+ |
| |
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1000| |0x1004|-+ |XXXXXX| |XXXXXX| |
+------+ +------+ | +------+ +------+ |
| |
+-----------------------------------+
Next we have:
s = &p;
s
is a pointer to pointer to int
and p
is a pointer to int
. So now s
points to p
:
i: 0x1000 j: 0x1004
+------+ +------+
+-->| 50 | | 100 |<------------------------------------+
| +------+ +------+ |
| |
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1000| |0x1004|-+ |0x1020| |XXXXXX| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
And next:
t = &s;
t
is a pointer to pointer to pointer to int
and s
is a pointer to pointer to int
. So now t
points to s
:
i: 0x1000 j: 0x1004
+------+ +------+
+-->| 50 | | 100 |<------------------------------------+
| +------+ +------+ |
| |
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1000| |0x1004|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
p = q;
We assign the content of q
to p
. That means that p
no longer points to i
, but it now points where q
points to, that is j
:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | +->| 100 |<------------------------------------+
+------+ | +------+ |
+-------------+ |
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1004| |0x1004|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
s = &q;
We assign s
to point to the address of q
. So, now s
no longer points to p
, instead it points to q
:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | +->| 100 |<------------------------------------+
+------+ | +------+ |
+-------------+ |
| k: 0x1008 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1004| |0x1004|-+ |0x1024|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+-----------+
Next:
p = k;
We assign the content of k
to p
. So now p
points to the location where k
points to, that is the first element of the array:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |<------------------------------------+
+------+ +------+ |
+-------------+ |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +->+------+------+------+------+------+ |
| |0x100C|---->| 10 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x100C| |0x1004|-+ |0x1024|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+-----------+
Next:
*p = *q;
This command says: "Get the content of the location where q
points to and assign it to the location where p
points to". q
points to j
, which is equal to 100, p
points to the first element of the array:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |<------------------------------------+
+------+ +------+ |
+-------------+ |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ +->+------+------+------+------+------+ |
| |0x100C|---->| 100 | 20 | 30 | 40 | 50 | |
| +------+ +------+------+------+------+------+ |
| |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x100C| |0x1004|-+ |0x1024|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+-----------+
Next:
p++;
This is the "tricky" command (although not so tricky when you realize what's going on). In normal conditions, this would increment the p
variable by 1. But because p
is a pointer, it will be incremented by the size of the type of the variable it (is supposed to) points to, so that p
points to the next memory location. In this case that is sizeof(int)
which is, let's say 4 (this is not necessarily true). So now p
points to the next cell of the array:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |<------------------------------------+
+------+ +------+ |
+-------------+ |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 20 | 30 | 40 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1010| |0x1004|-+ |0x1024|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+-----------+
Next:
s = &p
s
points to the location of p
:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |<------------------------------------+
+------+ +------+ |
+-------------+ |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 20 | 30 | 40 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1010| |0x1004|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
**s = 500;
This command says: "Go to the location where s
points to and get its content, let's call it *s
, then go to the location where *s
points to and assign the value 500. s
points to p
, and p
points to the 2nd array cell:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 |<------------------------------------+
+------+ +------+ |
+-------------+ |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 30 | 40 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1010| |0x1004|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
q = p + 2;
Again here, as of above, because q
and p
are pointers, this command assigns to q
the content of p
plus 2 * sizeof(int)
. p
points to the second array cell, so now q
points to the 4th array cell:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +-------------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 30 | 40 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1010| |0x1018|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
*q = 1000;
Go the location where q
points to and assign 1000:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +-------------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 30 | 1000 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1010| |0x1018|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
p = q - 1;
p
will now point to the previous location of where p
points to, that is the 3rd array cell:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +-------------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 30 | 1000 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x1018|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
*p = 750;
Go the location where p
points to and assign 750:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +-------------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 750 | 1000 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x1018|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
q++;
Same as above, move q
to point to the next memory location of where it points to, that is the 5th cell of the array:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 750 | 1000 | 50 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x101C|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
*q = *q * 100;
Go to the location where q
points to and get its content (50). Multiply it by 100 (=5000). Finally assign this value to the location where q
points to:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | 750 | 1000 | 5000 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x101C|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
**s = -100;
Go to the location where s
points to (p
) and get its content, let's call it *s
. Now go to the location where *s
points to (3rd array cell) and assign -100:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | -100 | 1000 | 5000 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x101C|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
Next:
***t = -200;
Go to the location where t
points to (s
) and get its content, let's call this *t
. Now go to the location where *t
points to (q
) and get its content, let's call this **t
. Now go to the location where **t
points to (the 3rd cell of the array again) and assign -200:
i: 0x1000 j: 0x1004
+------+ +------+
| 50 | | 100 | +------------+
+------+ +------+ | |
+-------------+ v |
| k: 0x1008 | 0x100C 0x1010 0x1014 0x1018 0x101C |
| +------+ | +------+------+------+------+------+ |
| |0x100C|--+->| 100 | 500 | -200 | 1000 | 5000 | |
| +------+ | +------+------+------+------+------+ |
| +-------------------^ |
| p: 0x1020 q: 0x1024 s: 0x1028 t: 0x102C |
| +------+ +------+ +------+ +------+ |
+---|0x1014| |0x101C|-+ |0x1020|<----|0x1028| |
+------+ +------+ | +------+ +------+ |
^ | | |
| +------+----------------------------+
| |
+------------------------+
I hope this answer clarifies things for you and others. Always draw memory when learning and playing with pointers, it will make your life A LOT easier.
Regards.
Upvotes: 5
Reputation: 1092
int main() {
int i = 50, j = 100;
int k[] = {10, 20, 30, 40, 50};
int *p, *q;
int **s;
int ***t;
p = &i;
printf("%d %d\n", i, *p); //50 50
q = &j;
printf("%d %d\n", j, *q); //100 100
s = &p;
printf("%d %d\n", *p, **s); // 50 50
t = &s;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
p = q;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
s = &q;
printf("%d %d %d %d\n", *p, *q, **s, ***t);
// k is a pointer to a memory where the array is stored
// in this case a memory with values [10,20,30,40,50]
// p will also point to this memory address
p = k;
// *q is j , p is pointing to the array => *p will be the first element of the array
// *p = *q => firts element of array will be j
// the new array will be [100,20,30,40,50]
*p = *q;
//in case of pointers, the ++ oprtator will act like this : p = p + sizeof(*p) wich means next int at that memory location, in our case, next element in array
//if we have p+2 , it will be translated as p + 2*sizeof(*p) which means the 3rd element of the array (k[2])
p++;
//s is pointer to p, p is pointer to 2nd element of array (k[1])
s = &p;
// **s = *p = k[1], our array will be [100,500,30,40,50]
**s = 500;
//now, we move p, 2 elements forwards, that means p = &k[3]
//q will point to k[3]
q = p + 2;
//k[3] will be 1000=> [100,500,30,1000,50]
*q = 1000;
//p will be &k[3] -1 => &k[2]
p = q - 1;
// k[2] = 750 => [100,500,750,1000,50]
*p = 750;
// q is &k[3], q++ will be next element , &k[4]
q ++;
// *(&k[4]) = *(&k[4]) * 100 => k[4] = k[4] * 100 => [100.500,750,1000,5000]
*q = *q * 100;
printf("%d %d %d %d %d\n", k[0], k[1], k[2], k[3], k[4]);
//s is &p (from line 33), p is k[2] => **s => *(*(&p)) =>*(*(&(&k[2])) => k[2]
// k[2] = -100
**s = -100;
//t is &s => *(*(*(*(&s)))) => *(*(*(&(&(&k[2]))))) => k[2]
// k[2] = -200
***t = -200;
printf("%d %d %d %d %d\n", k[0], k[1], k[2], k[3], k[4]);
//i is 50
//j is 100
//*p = *(&k[2]) = k[2] = -200
//*q = *(&k[4]) = k[4] = 5000
//**s = *(*(&p)) = **&&k[2] = -200
//***t = ***&s = **s = -200
printf("%d %d %d %d %d %d\n", i, j, *p, *q, **s, ***t);
return 0;
}
Upvotes: 0
Reputation: 1169
It helps to draw a graph to visualize things. I add the solution below, but to figure it out yourself just draw all relations in a graph.
p = k; // p now points at the first element of k (value=10)
*p = *q; // replace first element in k with *q (value=100) -> array now 100, 20, 30, ..
p++; // p now points to the second element of k
s = &p; // s points at p, p points at second element of k
**s = 500; // replace second element of k with 500 -> 100, 500, 30,..
q = p + 2; // q now points at 4th element of k (value=40)
*q = 1000; // set value to 1000 -> 100, 500, 30, 1000, 50
p = q - 1; // p now points to 3rd element
*p = 750; // set to 750 -> 100, 500, 750, 1000, 50
q++; // increase q, now points at 5th element
*q = *q * 100; // multiply value of 5th element by 100 -> 100, 500, 750, 1000, 5000
**s = -100; // s points to p, which points to 3rd element -> 100, 500, -100, 1000, 5000
***t = -200; // t points to s, so replace same value -> 100, 500, -200, 1000, 5000
Upvotes: 1