I have two question about the following code, in particular the int sum(const int *begin, const int *end) function. The thing that I don't understand is why is it that we assign p as a pointer to an immutable constant i.e. begin. But then we also have ++p in the for loop inside sum()? Why is it that it is ++p but not ++*p? And why is it that is is p!=end but not *p!= end?
I was reading that: "In const int *p, *p (content pointed-to) is constant, but p is not constant."
I don't quite understand the difference between the usages of *p and p in this function.
My second question is: What is the reason of declaring const in: const int *p = begin in the for loop of int sum(...)? Is it because in the signature of int sum(...), there is this const being declared for: const int *p = begin ? I.e. is it because begin is being declared as something that is immutable - so that's why in the for loop, we have to declare begin is an immutable constant pointed to by the pointer *p?
/* Function to compute the sum of a range of an array (SumArrayRange.cpp) */
#include <iostream>
using namespace std;
// Function prototype
int sum(const int *begin, const int *end);
// Test Driver
int main() {
int a[] = {8, 4, 5, 3, 2, 1, 4, 8};
cout << sum(a, a+8) << endl; // a[0] to a[7]
cout << sum(a+2, a+5) << endl; // a[2] to a[4]
cout << sum(&a[2], &a[5]) << endl; // a[2] to a[4]
}
// Function definition
// Return the sum of the given array of the range from
// begin to end, exclude end.
int sum(const int *begin, const int *end) {
int sum = 0;
for (const int *p = begin; p != end; ++p) {
sum += *p;
}
return sum;
}
As a reminder, the table of const and pointers:
int * p -- Pointer to a mutable (read/write) location. Pointer and target data may be modified.
int const * p -- Pointer to read only location. The data at the location constant, read-only.
int * const p -- Constant pointer to read/write location. Pointer can't be changed, but data at location may be changed.
int const * const p -- Constant pointer to constant data. Neither pointer nor data may be changed.
In the declaration:
int sum(const int *begin, const int *end);
The pointers are mutable pointers to constant data. The pointers may be modified, but they point to constant (read-only) data.
Edit 1: Incrementing a pointer
Let's assign a pointer, p, the value of 0x12.
Integers will be 4 bytes in length:
+---+
p -> | 1 | 0x12
+---+
| 2 | 0x13
+---+
| 3 | 0x14
+---+
| 4 | 0x15
+---+
| 0 | 0x16
+---+
| 6 | 0x17
+---+
| 1 | 0x18
+---+
| 9 | 0x19
+---+
The integer at *p == 1234 (provided Big Endian layout).
Incrementing p will produce the address: 0x12 + 1 * sizeof(int), or
0x12 + 1 * (4) == 0x16.
+---+
p -> | 1 | 0x12
+---+
| 2 | 0x13
+---+
| 3 | 0x14
+---+
| 4 | 0x15
+---+
p + 1 -> | 0 | 0x16
+---+
| 6 | 0x17
+---+
| 1 | 0x18
+---+
| 9 | 0x19
+---+
Edit 2: Alignment
There is an issue of alignment at this perspective.
Let's assume the processor is 32-bits. It has an internal register (word) size of 32 bits (4 octets). The processor is defined to fetch 32-bits out of memory.
Let us store integers at addresses 4, 8, 12 and 16. The binary representation of those addresses:
0000 0100 -- 4
0000 1000 -- 8
0000 1100 -- 12
0001 0000 -- 16
As you can see, the rightmost 2 bits are always zero. The processor designer's don't need to implement the 2 rightmost address lines (thus saving money and real estate space). In this processor, fetches at address evenly divisible by 4 are most efficient (1 fetch). They are aligned to a 4-byte boundary.
Related
I am required to add two select only two numbers from a Variable ie 0X11223344 and I want my pointers to pick 22 in the middle of the array. how do I go about it
You can use shift and modulo operations to get the value
int main(){
return (0X11223344 >> 16) % 256;
}
The program returns 34 == 0x22
A right shift of 4 removes 1 digit. A right shift of 16 removes 4 digits. A modulo of 16 removes all but one digits. A modulo of 16*16= 256 removes all but 2 digits.
You can also get the value with pointer operations:
int main() {
int endianness = 2;
int a = 0x11223344;
char *b = ((char *) &a) + endianness;
return *b;
}
The value of endianess is implementation defined. On a system with little endiannes it's 2
|01 02 03 04| memory address
-------------
|44 33 22 11| 4 byte int with address 01 and value 0x11223344
| | |22| | 1 byte char with address 03 and value 0x22
and on a system with big endianness it's 1
|01 02 03 04| memory address
-------------
|11 22 33 44| 4 byte int with address 01 and value 0x11223344
| |22| | | 1 byte char with address 02 and value 0x22
This question already has answers here:
What does "dereferencing" a pointer mean?
(6 answers)
Closed 5 years ago.
The below algorithm can output 99 0000
Would you please let me know how does this following line of code work?
*(long*)&(st->flag1) = 0;
The algorithm is:
#include <stdio.h>
struct SpecialFlags{
int id;
char flag1;
char flag2;
char flag3;
char flag4;
};
void ClearFlags( SpecialFlags *st )
{
*(long*)&(st->flag1) = 0;
}
int main(void)
{
SpecialFlags flags;
flags.id = 99;
flags.flag1 = 1;
flags.flag2 = 2;
flags.flag3 = 3;
flags.flag4 = 4;
ClearFlags( &flags );
printf( "%d %d%d%d%d\n", flags.id,
flags.flag1, flags.flag2,
flags.flag3, flags.flag4 );
return 0;
}
In the Below structure
struct SpecialFlags{
int id;
char flag1;
char flag2;
char flag3;
char flag4;
};
id flag1 flag2 flag3 flag4
--------------------------------------------------
| 99 | 1(49) | 2(50) | 3(51) | 4(52) |
---------------------------------------------------
0x100 0x104 0x105 0x106 0x107 0x108 <--lets say starting address is 0x100
When ClearFlags() is called st points to beginning of the structure. And when you do *(long*)&(st->flag1) = 0; First address of st->flags1(char type) gets converted to long* type that means it will fetch 4 bytes at a time and finally * means value in that 4 bytes.
From above figure
(long*)&(st->flag1) => from 0x104 address till next 4 byte i.e till 0x108
*(long*)&(st->flag1) => what value is there in between 0x104 location to 0x108 location
*(long*)&(st->flag1) = 0 => what value is there in between 0x104 location to 0x108 location, will be overwritten with 0(zero)
After this statement your structure looks like
id flag1 flag2 flag3 flag4
--------------------------------------------------
| 99 | 0(48) | 0(48) | 0(48) | 0(48) |
---------------------------------------------------
0x100 0x104 0x105 0x106 0x107 0x108
Now when you prints flags.flag1, flags.flag2.. it prints 0.
If I have a large array where the data streams are interleaved in some complex fashion, can I define a pointer p such that p + 1 is some arbitrary offset b bytes.
For example lets say I have 1,000,000 ints, 4 bytes each.
int* p_int = my_int_array;
This gives me *(p_int+1) == my_int_array[1] (moves 4 bytes)
I am looking for something like
something_here(b)* big_span_p_int = my_int_array;
which would make *(big_span_p_int + 1) == my_int_array[b] (moves 4*b or b bytes, whichever is possible or easier)
Is this possible? easy?
Thanks for the help.
EDIT:
b is compile time variable.
Using some of your code. There is no need to declare an additional pointer/array. Applying pointer arithmetic on p_int is enough to traverse and reach the number value you are seeking.
Let's look at this example:
int main() {
int my_int_array[5] {1,2,3,4,5};
int* p_int = my_int_array;
int b = 2;
std::cout << *(p_int + b) << std::endl; // Output is 3, because *p_int == my_int_array[0], so my_int_array[2] will give you the third index of the array.
}
Graphically represented:
Memory Address | Stored Value (values or memory addresses)
----------------------------------------------
0 | .....
1 | .....
2 | .....
3 | .....
4 | .....
5 | .....
6 | .....
7 | .....
8 | .....
. | .....
. | .....
. | .....
n-1 | .....
Imagine the memory as being a very big array in which you can access positions by its memory address (in this case we've simplified the addresses to natural numbers. In reality they're hexadecimal values). "n" is the total amount (or size) of the memory. Since Memory counts and starts in 0, size is equivalent to n-1.
Using the example above:
1. When you invoke:
int my_int_array[5] {1,2,3,4,5};
The Operating System and the C++ compiler allocates the integer array memory statically for you, but we can think that our memory has been changed. E.g. Memory address 2 (decided by the compiler) now has our first value of my_int_array.
Memory Address | Name - Stored Value (values or memory addresses)
-----------------------------------------------------
0 | .....
1 | .....
2 | my_int_array[0] = 1
3 | my_int_array[1] = 2
4 | my_int_array[2] = 3
5 | my_int_array[3] = 4
6 | my_int_array[4] = 5
7 | .....
8 | .....
. | .....
. | .....
. | .....
n-1 | .....
2. Now if we say:
int* p_int = my_int_array;
The memory changes again. E.g. Memory address 8 (decided by the compiler) now has a int pointer called *p_int.
Memory Address | Name - Stored Value (values or memory addresses)
-----------------------------------------------------
0 | .....
1 | .....
2 | my_int_array[0] = 1
3 | my_int_array[1] = 2
4 | my_int_array[2] = 3
5 | my_int_array[3] = 4
6 | my_int_array[4] = 5
7 | .....
8 | p_int = 2 (which means it points to memory address 2, which has the value of my_int_array[0] = 1)
. | .....
. | .....
. | .....
n-1 | .....
3. If in your program you now say:
p_int += 2; // You increase the value by 2 (or 8 bytes), it now points elsewhere, 2 index values ahead in the array.
Memory Address | Name - Stored Value (values or memory addresses)
-----------------------------------------------------
0 | .....
1 | .....
2 | my_int_array[0] = 1
3 | my_int_array[1] = 2
4 | my_int_array[2] = 3
5 | my_int_array[3] = 4
6 | my_int_array[4] = 5
7 | .....
8 | p_int = 4 (which means it points to memory address 4, which has the value of my_int_array[2] = 3)
. | .....
. | .....
. | .....
n-1 | .....
When doing memory allocation and pointer arithmetic in a simple case like this, you don't have to worry about the size in bytes of an int (4 bytes). The pointers here are already bound to a type (in this case int) when you declared them, so just by increasing their value by integer values, p_int + 1, this will make point p_int point to the next 4 bytes or int value. Just by adding the values to the pointers you will get the next integer.
If b is a constant expression (a compile-time constant), then pointer declared as
int (*big_span_p_int)[b]
will move by b * sizeof(int) bytes every time you increment it.
In C you can use a run-time value in place of b, but since your question is tagged [C++], this is not applicable.
I have a 2D matrix
matrix[m][n];
I know that matrix is a double pointer with type int**. I would like to obtain a double pointer pointing to a submatrix of the original matrix. For example, I want the submatrix to start for cell (1,1). How do I get such a double pointer from the original matrix[m][n]?
I know that matrix is a double pointer with type int**.
No, you don't. Arrays are not pointers. If you declared it as int matrix[m][n];, then the type of the expression matrix is int [m][n]; unless matrix is the operand of the sizeof or unary & operators, it will have its type converted ("decay") to int (*)[n] (pointer to n-element array of int).
The problem is that you can't create arbitrary submatrices by just declaring a pointer of the right type; C and C++ don't provide an easy way to "slice" arrays this way. You can certainly create a pointer of type int (*)[n-1] and assign the value of &matrix[1][1] to it (with an appropriate cast), but it won't do what you want.
EDIT
Now that I have a real keyboard in front of me I can expand on this a little bit.
Let's imagine a 3x3 matrix declared as follows:
int m[3][3] = {{0,1,2},{3,4,5},{6,7,8}};
We normally visualize such a matrix as
+---+---+---+
| 0 | 1 | 2 |
+---+---+---+
| 3 | 4 | 5 |
+---+---+---+
| 6 | 7 | 8 |
+---+---+---+
In C and C++, 2-dimensional arrays are laid out in row-major order1, 2, so the above matrix would be represented in memory as
+---+
m: | 0 | m[0][0]
+---+
| 1 | m[0][1]
+---+
| 2 | m[0][2]
+---+
| 3 | m[1][0]
+---+
| 4 | m[1][1]
+---+
| 5 | m[1][2]
+---+
| 6 | m[2][0]
+---+
| 7 | m[2][1]
+---+
| 8 | m[2][2]
+---+
So suppose you want the 2x2 submatrix starting at m[1][1]:
+---+---+---+
| 0 | 1 | 2 |
+---+---+---+
| 3 | +---+---+
+---+ | 4 | 5 |
| 6 | +---+---+
+---+ | 7 | 8 |
+---+---+
That corresponds to the following array elements:
+---+
m: | 0 | m[0][0]
+---+
| 1 | m[0][1]
+---+
| 2 | m[0][2]
+---+
| 3 | m[1][0]
+---+
+---+
| 4 | m[1][1]
+---+
| 5 | m[1][2]
+---+
+---+
| 6 | m[2][0]
+---+
+---+
| 7 | m[2][1]
+---+
| 8 | m[2][2]
+---+
That's not a contiguous subarray within m, so just declaring a pointer and setting it to &m[1][1] won't do what you really want. You'll need to create a separate matrix object and copy the elements you want to it:
int subm[2][2] = {{m[1][1], m[1][2]}, {m[2][1], m[2][2]}};
You can write a function to grab a 2x2 "slice" of your matrix like so:
void slice2x2( int (*mat)[3], int (*submat)[2], size_t startx, size_t starty )
{
for ( size_t i = 0; i < 2; i++ )
for ( size_t j = 0; j < 2; j++ )
submat[i][j] = mat[startx + i][starty + j];
}
int main( void )
{
int matrix[3][3] = {{0,1,2},{3,4,5},{6,7,8}};
int submat[2][2];
slice2x2( matrix, submat, 1, 1 );
// do something with submat
}
Pre-publication draft of the C 2011 standard, §6.2.5.1, ¶3.
Pre-publication draft of the C++ 2014 standard, §8.3.4, ¶9
A matrix defined as 2D array of constant size:
int matrix [m][n];
is stored as m contiguous blocks of n elements. You can therefore imagine this technically as a flat sequence of m*n elements in memory. You can use pointer arithmetic to find the start of a row, or to find a specific element. But you can't locate a submatrix int that way.
The "double" pointer:
int **pmatrix;
obeys a different logic: it is a pointer to a pointer and works as an array of m pointers pointing at lines of n consecutive elements. So your elements are not necessarily consecutive. You can use pointer arithmetic and indirection to locate the start of a row or a specific item. But again this can't address a submatrix.
Both matrix and pmatrix can be used with 1D or 2D indexing, but the compiler generates different code to address the elements.
For getting sub-matrices you have to make iterations to find the right elements, using vertical and horizontal offsets, but you can't imagine to pass somehow a pointer to the sub-matrix if you don't copy the right elements in a new matrix of target's size.
#include<stdio.h>
#include<iostream.h>
main()
{
unsigned char c,i;
union temp
{
float f;
char c[4];
} k;
cin>>k.f;
c=128;
for(i=0;i<8;i++)
{
if(k.c[3] & c) cout<<'1';
else cout<<'0';
c=c>>1;
}
c=128;
cout<<'\n';
for(i=0;i<8;i++)
{
if(k.c[2] & c) cout<<'1';
else cout<<'0';
c=c>>1;
}
return 0;
}
if(k.c[2] & c)
That is called bitwise AND.
Illustration of bitwise AND
//illustration : mathematics of bitwise AND
a = 10110101 (binary representation)
b = 10011010 (binary representation)
c = a & b
= 10110101 & 10011010
= 10010000 (binary representation)
= 128 + 16 (decimal)
= 144 (decimal)
Bitwise AND uses this truth table:
X | Y | R = X & Y
---------
0 | 0 | 0
0 | 1 | 0
1 | 0 | 0
1 | 1 | 1
See these tutorials on bitwise AND:
Bitwise Operators in C and C++: A Tutorial
Bitwise AND operator &
A bitwise operation (AND in this case) perform a bit by bit operation between the 2 operands.
For example the & :
11010010 &
11000110 =
11000010
Bitwise Operation in your code
c = 128 therefore the binary representation is
c = 10000000
a & c will and every ith but if c with evert ith bit of a. Because c only has 1 in the MSB position (pos 7), so a & c will be non-zero if a has a 1 in its position 7 bit, if a has a 0 in pos bit, then a & c will be zero. This logic is used in the if block above. The if block is entered depending upon if the MSB (position 7 bit) of the byte is 1 or not.
Suppose a = ? ? ? ? ? ? ? ? where a ? is either 0 or 1
Then
a = ? ? ? ? ? ? ? ?
AND & & & & & & & &
c = 1 0 0 0 0 0 0 0
---------------
? 0 0 0 0 0 0 0
As 0 & ? = 0. So if the bit position 7 is 0 then answer is 0 is bit position 7 is 1 then answer is 1.
In each iteration c is shifted left one position, so the 1 in the c propagates left wise. So in each iteration masking with the other variable you are able to know if there is a 1 or a 0 at that position of the variable.
Use in your code
You have
union temp
{
float f;
char c[4];
} k;
Inside the union the float and the char c[4] share the same memory location (as the property of union).
Now, sizeof (f) = 4bytes) You assign k.f = 5345341 or whatever . When you access the array k.arr[0] it will access the 0th byte of the float f, when you do k.arr[1] it access the 1st byte of the float f . The array is not empty as both the float and the array points the same memory location but access differently. This is actually a mechanism to access the 4 bytes of float bytewise.
NOTE THAT k.arr[0] may address the last byte instead of 1st byte (as told above), this depends on the byte ordering of storage in memory (See little endian and big endian byte ordering for this)
Union k
+--------+--------+--------+--------+ --+
| arr[0] | arr[1] | arr[2] | arr[3] | |
+--------+--------+--------+--------+ |---> Shares same location (in little endian)
| float f | |
+-----------------------------------+ --+
Or the byte ordering could be reversed
Union k
+--------+--------+--------+--------+ --+
| arr[3] | arr[2] | arr[1] | arr[0] | |
+--------+--------+--------+--------+ |---> Shares same location (in big endian)
| float f | |
+-----------------------------------+ --+
Your code loops on this and shifts the c which propagates the only 1 in the c from bit 7 to bit 0 in one step at a time in each location, and the bitwise anding checks actually every bit position of the bytes of the float variable f, and prints a 1 if it is 1 else 0.
If you print all the 4 bytes of the float, then you can see the IEEE 754 representation.
c has single bit in it set. 128 is 10000000 in binary. if(k.c[2] & c) checks if that bit is set in k.c[2] as well. Then the bit in c is shifted around to check for other bits.
As result the program is made to display the binary representation of float it seems.