So recently in class, we were introduced to pointers and heaps and how they work. A question I have is why cant we cout a dereferenced pointer in that array? For example, in the code below:
#include <iostream>
using namespace std;
int main() {
double* p = new double[2];
*(p + 0) = 37.5;
*(p + 1) = 101.4;
for (int i = 0; i < 2; i++)
cout << *p[i] << endl;
return 0;
}
Why doesn't cout << *p[i] work but cout << *(p + i) does?
In C, the name of an array is a pointer to the first element. C++ inherited that from C. In your program, p is the pointer to the first element of the array. So you either do pointer arithmetics as you did when setting the elements (e. g. *(p + 1) = 101.4;) or you use the subscript operator ([]) to do the arithmetics: *(p + i) is the same as p[i]. The compiler translates p[i] to 1) adding i to p and then 2) access the address that resulted from the sum. That is exactly what you have written: *(p + 1). The statement in the parentheses is calculated first and the reference operator is applied to this result. That is exactly what happens if you use the index operator instead. So your loop has to look like this:
for (int i = 0; i < 2; i++)
{
std::cout << p[i] << std::endl;
}
Because of the precedence of operators your statement *p[i] translates to *(p[i]). So this statement tries to use the double read from the array as an address that shall be accessed. That this is not possible, is obvious (hopefully).
Got it?
P.S.: And please, do yourself a favor and ALWAYS surround the body of for/while/if statements with curly brackets. That saves you a LOT of time (especially debugging your own nonsense). Trust me, it is true.
p[1] = *(p + 1)
it is what you want to do. The [] operator already dereferences.
*p[1] = *(*(p + 1))
it tries to dereference a double Wich cannot happen
cout << p[i];
should work as you expect
because *p[i] basically is *(*(p + i))
read here for me https://www.tutorialspoint.com/cplusplus/cpp_pointer_arithmatic.htm
http://www.learncpp.com/cpp-tutorial/6-8a-pointer-arithmetic-and-array-indexing/
Note that p[i] is same as *(p+i).
Now *p[i] is meaningless, unless p[i] itself points to a different location, for e.g.
int t=0;
for(int i = 0; i < 2 ;i++)
p[i] = &t;
cout << *p[i] << "is nothing but value of t" << endl;
I hope it is clear.
Related
I'm learning c++ using the book:Programming Principles and Practice using C++ by Bjarne Stroustrup.
In Chapter 19, exercise 1
implement strdup() functions which will copy a c strings into another using only de-referencing method (not subscripting).
My copying doesn't print anything I've been look for answers for days.
Please anyone can help me?
Below is the entire code:-
#include <iostream>
using namespace std;
char* strdup(const char* q) {
// count the size
int n {0};
while(q[n]) {
++n;
}
// allocate memory
char* p = new char[n+1];
// copy q into p
while(*q) {
*p++ = *q++;
}
// terminator at the end
p[n] = 0;
return p;
}
int main()
{
const char* p = "welcome";
cout << "p:" << p << endl;
const char* q = strdup(p);
cout << "q:" << q << endl;
// check to see if q get new address
cout << "&p:" << &p << endl;
cout << "&q:" << &q << endl;
return 0;
}
using only de-referencing method (not subscripting)
So this is already wrong, because is uses the subscript operator []:
// count the size
int n {0};
while(q[n]) {
++n;
}
I just don't know how to turn the pointer back to the first char.
Well, there are two basic approaches:
stop damaging your original pointer in the first place. You can introduce new variables, remember?
char* p_begin = new char[n+1];
char* p_end = p_begin + n + 1; // copy the terminator too
for (char *tmp = p_begin; tmp != p_end; *tmp++ = *q++) ;
return p_begin;
you know exactly how far to move p to get back to the original value, because you already calculated how long the string is!
while(*q) {
*p++ = *q++;
}
*p = 0; // you already moved p and aren't supposed to be subscripting anyway
return p - n;
Finally, you can get the size without subscripting using exactly the same technique: either you use a temporary variable to find the terminator, or if you advance q as you go, then subtract n from it again at the end.
Oh, and if you're having trouble visualizing the values of all your variables - learn to use a debugger (or just add lots of print statements). You need to understand how your state changes over time, and watching it is much more helpful than just observing the result of a black box and trying to guess what happened inside.
Replace this:
while(*q) {
*p++ = *q++;
}
..with this:
for (int i = 0; i < n; i++) {
p[i] = q[i];
}
Problem solved.
having some understanding issues with the next block of code.
#include<iostream>
using namespace std;
int main() {
char *str = "hi";
char *p = new char[strlen(str) + 1];
for (int i = 0; *(str + i); i++)
*(p + i) = *(str + i);
cout << p << endl;
return 0;
}
Here's the result:
hi═¤¤¤¤
When i'm using debugger, i can see that my p points to an array of like 10 or 15 or some other amount of symbols (depends on compilation), so i'm getting extra symbols after "hi". BUT, when i'm using strcpy():
#include<iostream>
using namespace std;
int main() {
char *str = "hi";
char *p = new char[strlen(str) + 1];
strcpy(p, str);
cout << p << endl;
return 0;
}
i'm getting the result:
hi
So, can someone, please, explain to me, why am i getting such a result with the first example of a program and how to rework it to get the result like in the second example.
Thanks in advance.
The answer is in the stopping condition of the loop, i.e. *(str + i):
for (int i = 0 ; *(str + i) ; i++)
*(p + i) = *(str + i);
Note that there is no comparison operator in the expression. When an expression like this is used in a context where a logical condition is required, there is an implicit comparison to zero, i.e. *(str + i) means the same thing as *(str + i) != 0.
Now it should be clear why the string remains unterminated: loop stops when it discovers null terminator, and does not copy it into the destination string.
A slightly more "cryptic" way of doing the same thing would be coupling the comparison with the assignment, the way K&R book did:
for (int i = 0 ; *(p + i) = *(str + i) ; i++)
;
Now the null test happens after the assignment, ensuring that the destination is null-terminated.
You are not adding the terminating null character to p.
Add the line
*(p + i) = '\0';
after the for loop. However, to do that, you have to declare i before the for loop.
int i = 0;
for (i = 0; *(str + i); i++)
*(p + i) = *(str + i);
*(p + i) = '\0';
cout << p << endl;
You forgot to terminate the string in your first exaple with a zero:
#include <cstddef>
#include <iostream>
int main()
{
char const *str = "hi";
std::size_t length = std::strlen(str);
char *p = new char[length + 1];
for (std::size_t i = 0; i < length; ++i)
p[i] = str[i];
str[length] = '\0';
std::cout << p << '\n';
delete[] p;
}
Please mind: String literals are immutable so they should be pointed to by char const*s. The correct type to hold sizes of objects in memory or indexes into them is std::size_t, not int. If you do manual memory management you have to make sure that you free the allocated memory by passing pointers obtained using new to delete and pointers from new[] to delete[].
You shouldn't do memory management manually though. Use containers like std::string or std::vector or at least smart pointers like std::shared_ptr<> or std::unique_ptr<>.
So This Is What I Ended up coming up with for it. I currently can't figure out how to put my reverseArray function into the main... If i just copy and paste the code into it, it crashes every time it's run... I don't know why it causes it to crash or anything. Thank you everyone that has helped me so far with this.
using namespace std;
// Prototype for printArray goes here
void reverseArray(int*, int);
void printArray(int*, int);
int main()
{
int size; // size of the dynamically allocated array
// Declare as needed for a dynamically allocated array of
ints named "data".
// Declare other variables as needed
// Edit to display your own name
cout << "" << endl << endl;
// Prompt the user for the array size
cout << "Array size: ";
cin >> size;
// Add code to validate array size, so it is greater than one
while (size < 2)
{
cout << "Array size must be greater than 1: ";
cin >> size;
}
// Add code to dynamically allocate "data". Don't forget to release the memory before
// the program ends
int *data = new int[size],
*p = data;
// Write a loop to fill the "data" array with random numbers from 1 - 100 (inclusive)
// This code must use POINTER NOTATION (no subscripting) to work with the array.
// Reminder: neither of these notations is acceptable here:
// data[n] or *(data + n)
// Instead this code will use pointer incrementing/decrementing and dereferencing
for (int i = 0; i < size; i++, p++)
{
*p = rand() % 100 + 1;
}
// Call function to print the original "data" array
cout << "\nOriginal array:\n" << endl;
printArray(data, size);
// Reset "data" to point to the beginning of the array
// Add code to reverse the array. Use 2 pointers: one starts at the beginning of the array and
// moves forward, the other starts at its last element and works backward. Swap the values they
// point to.
// Reminder: neither of these notations is acceptable here:
// data[n] or *(data + n)
// Instead this code will use pointer incrementing/decrementing and dereferencing
// For this, I made the function reverseArray instead of coding it in main.
reverseArray(data, size);
cout << endl;
cout << "\nReversed array:\n" << endl;
printArray(data, size);
cout << endl << endl;
// Finish up
delete[] data;
system("pause");
return 0;
}
// Function printArray() goes here. Print the array, 5 numbers per line,
right-aligned
void printArray(int*p, int size)
{
for (int i = 0; i < size; i++, p++)
{
cout << setw(5) << right << *p;
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
}
// Function reverseArray() Reverses the array.
void reverseArray(int *data, int size)
{
int *e = data + size - 1; // Pointer at the end
for (; e > data; data++, e--) // while end pointer (e)> start pointer, swap start w/ end
{
int arrayFlip = *data;
*data = *e;
*e = arrayFlip;
}
}
You may be torturing yourself for no reason, or beating your head into a brick wall (don't worry - we've all been there... and have the bruises to prove it.)
First, lets start with any allocated block of memory, say:
int *a = new int[NELEM], ...
What is a? (a pointer -- yes, but to what?) It is a pointer to the beginning address in a block of memory, NELEM * sizeof *a bytes in size. What type of pointer is it? (int). How many bytes per-int? (generally 4).
So why is having the pointer be type int important? (well, it sets the type-size that controls how pointer-arithmetic operates when referencing the block of memory though that pointer) Meaning since your pointer type is int, the compiler knows that a + 1 is a + 4-bytes which allows you to reference the next value in your block of memory.
OK, but I allocated memory for a, what are my responsibilities with regard to a? In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
What does that mean to me? It means that if you cannot simply increment a (e.g. a++) in the scope where a was declared. If you do, you have lost your reference to the beginning address of the block and that block can no longer be freed (that's a memory leak).
So if I cannot use any indexing (e.g. a[i] or *(a + i)) and I can't increment my pointer a -- then what are my options? Use another pointer..., e.g.
int *a = new int[NELEM],
*p = a;
...
std::cout << "array : ";
for (int i = 0; i < NELEM; i++, p++) {
*p = rand() % 100 + 1;
std::cout << std::setw(5) << *p;
}
std::cout << '\n';
Have you satisfied your responsibilities regarding the block of memory you assigned to a? Sure, a still points to the beginning address of the block, so it can be freed. All you did was use a second pointer p and iterated using p leaving a unchanged.
Hmm.. Using a second pointer.. I wonder if I can reverse my array using that same scheme. Yep. In it simplest form, you could do something like:
void rev (int *a, size_t size)
{
int *e = a + size - 1; /* end pointer */
for (; e > a; a++, e--) { /* while end > start, swap start, end */
int tmp = *a;
*a = *e;
*e = tmp;
}
}
But wait!! You said you couldn't increment a without losing the starting address to my allocated block -- how can I free it now? (a in main() never changes, the function rev receives a copy of a and within rev you are free to increment/decrement or do whatever you like to a, within the bounds of the block of memory, because a in rev has its very own (and very different) address from your original pointer in main().
(an aside...) You could have declared a third pointer within rev, e.g.
int *s = a, /* start pointer */
*e = a + size - 1; /* end pointer */
and then used s instead of a in your iteration and swap, but there isn't any need to. You are free to do it that way if it is more clear to you which pointer you are working with. It's simply another 8-bytes (or 4 on x86), so the additional storage is a non-issue.
Putting it altogether in a short example, you could do something similar to the following:
#include <iostream>
#include <iomanip>
#include <cstdlib>
#define NELEM 10
void rev (int *a, size_t size)
{
int *e = a + size - 1; /* end pointer */
for (; e > a; a++, e--) { /* while end > start, swap start, end */
int tmp = *a;
*a = *e;
*e = tmp;
}
}
int main (void) {
int *a = new int[NELEM],
*p = a;
srand (20180502);
std::cout << "array : ";
for (int i = 0; i < NELEM; i++, p++) {
*p = rand() % 100 + 1;
std::cout << std::setw(5) << *p;
}
std::cout << '\n';
rev (a, NELEM);
p = a;
std::cout << "reverse: ";
for (int i = 0; i < NELEM; i++, p++)
std::cout << std::setw(5) << *p;
std::cout << '\n';
delete[] a;
}
Example Use/Output
$ ./bin/array_reverse
array : 11 6 78 93 25 71 82 58 97 68
reverse: 68 97 58 82 71 25 93 78 6 11
All of this takes a bit of time to sink in. We all have bruises on our foreheads from the same wall. Just make peace with the fact that a pointer is just a variable that holds the address of something else as it value (e.g. it points to where something else is stored).
Understand how the type of the pointer effects the pointer-arithmetic (and indexing), e.g. how many bytes are advanced with p++ or in for (i = 0; i < size; i++) p[i], and make sure you know exactly where your pointer is pointing and things should start to fall into place.
If you ever have any problems figuring out what is going on with your pointer, pull out an 8.5 x 11 sheet of paper and a No.2 pencil and just draw it out -- on each iteration fill in the block where your pointer is pointing, etc.. -- it really helps. Once you have drawn enough diagrams, done enough linked-lists, stacks, etc... you won't need the paper as much as you do now (you will still need it -- so keep it handy)
Reversing in main() with a Function
In response to your comment, when you look at main(), you already have an additional pointer p declared. So you can simply use that as your start pointer and add e from from the rev() function as your end-pointer. A simple implementation would be:
int main (void) {
int *a = new int[NELEM],
*p = a,
*e = a + NELEM - 1;;
srand (20180502);
std::cout << "array : ";
for (int i = 0; i < NELEM; i++, p++) {
*p = rand() % 100 + 1;
std::cout << std::setw(5) << *p;
}
std::cout << '\n';
p = a; /* reset pointer */
for (; e > p; p++, e--) { /* reverse array */
int tmp = *p;
*p = *e;
*e = tmp;
}
p = a; /* reset pointer -- again */
std::cout << "reverse: ";
for (int i = 0; i < NELEM; i++, p++)
std::cout << std::setw(5) << *p;
std::cout << '\n';
delete[] a;
}
(same output)
Look things over and let me know if you have further questions.
The following lines in main are not correct.
*data = rand() % 100 + 1;
cout << setw(5) << right << *data;
They just set the value of the first element of the array and print the same element.
Use data[i] instead.
data[i] = rand() % 100 + 1;
cout << setw(5) << right << data[i];
If you must use the pointer notation, use *(data+i).
*(data+i) = rand() % 100 + 1;
cout << setw(5) << right << *(data+i);
Another method you can use is to use a temporary pointer variable just for iterating over the array.
int* iter = data;
for (int i = 0; i < size; i++. ++iter)
{
*iter = rand() % 100 + 1;
cout << setw(5) << right << *iter;
...
}
This makes sure that you don't lose the original pointer, which is necessary to be able to deallocate the memory.
PS There may be other errors, or not, but I noticed the above problem after a quick glance through your code.
Moving A Pointer
data++;
and
data--;
mostly. There are other things you could do, but your instructor asked for increment and decrement.
So
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data;
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
becomes
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data++; // change made here
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
Note only one data++, and it's on the second use of data. You should be able to figure out why.
Resetting A Pointer
The easiest and most obvious is to
int*reset = data;
then you can data around to your heart's content, and when you want to reset,
data = reset;
So the above loops wind up looking like
int*reset = data;
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data++; // change made here
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
data = reset;
But... You can also separate your logic out into functions and take advantage of pass by value
void fill(int * data,
int size)
{
for (int i = 0; i < size; i++)
{
*data = rand() % 100 + 1;
cout << setw(5) << right << *data++; // change made here
if ((i + 1) % 5 == 0)
{
cout << endl;
}
}
}
and the related part of main now looks something like
data = new int[size];
// Write a loop to fill the "data" array with random numbers from 1 - 100 (inclusive)
// This code must use POINTER NOTATION (no subscripting) to work with the array.
// Reminder: neither of these notations is acceptable here:
// data[n] or *(data + n)
// Instead this code will use pointer incrementing/decrementing and dereferencing
cout << "This is just the test to see if the pointer is successfully creating the array" << endl;
fill(data, size);
// Reset "data" to point to the beginning of the array
"Just wait a minute!" you're thinking. "How in Crom's name is int * data pass by value? That's a <expletive deleted>ing pointer!" The data pointed at is passed by reference, but the pointer itself is passed by value. data in fill is a copy of data in main. All of the data++ing in fill happens to a copy, so data in main is still pointing right where you left it.
No reset required and you've simplified main's responsibilities by spinning off part of them to their own simple and independently testable function. Keeping everything as simple, small, and stupid as possible is worth it's weight in bitcoin in my view.
I have an integer array: int* b whose values are set for elements 0 through 7. When I print out each element individually, I get the correct elements. However, when I use a for loop, I am getting different results. Any idea why?
Here's the code:
//toBinary(int x) returns an int pointer whose value is an array of size 8: int ret[8]
int* b = toBinary(55);
//Print method 1 (Individual printout)
cout << b[0] << b[1] << b[2] << b[3] << b[4] << b[5] << b[6] << b[7] << endl;
//Print method 2 (for loop)
for (int t = 0; t < 8; t++)
cout << b[t];
cout << endl;
The result of the first print out is the following: 00110111
This is the correct printout.
When I print using the second technique, it says, -858993460-85899346051202679591765470927361022170810222364 This is the wrong printout.
Why am I getting two different printouts?
Here is the toBinary method:
int* toBinary(int i) {
int byte[8];
for (int bit = 7; bit >= 0; bit--) {
if (i - pow(2, bit) >= 0) {
byte[7-bit] = 1;
i -= pow(2, bit);
}
else
byte[7-bit] = 0;
}
return byte;
}
The toBinary method returns the address of a local variable. byte will be deleted when the function exits.
The fact that your first output works seems to be just luck because the memory segment wasn't used by anything else at that point.
To fix this, you'll either have to allocate the array on the heap manually or you use one of the containers (std::array, std::vector).
Other answers already touched on what the problem is here, I want to emphasize that your code is anti-modern C++, you should really be using std::vector (or std::array if you have C++11) which will solve all of these things instantly:
#include <vector>
std::vector<int> toBinary(int i) {
std::vector<int> byte(8);
for (int bit = 7; bit >= 0; bit--) {
if (i - pow(2, bit) >= 0) {
byte[7-bit] = 1;
i -= pow(2, bit);
}
else
byte[7-bit] = 0;
}
return byte;
}
And then..
std::vector<int> b = toBinary(55);
//Print method 1 (Individual printout)
cout << b[0] << b[1] << b[2] << b[3] << b[4] << b[5] << b[6] << b[7] << endl;
//Print method 2 (for loop)
for (int t = 0; t < 8; t++)
cout << b[t];
cout << endl;
Through toBinary you are returning a local variable that gets freed once the function call ends. You must allocate memory for the array using heap. And then return that pointer and collect it in the variable b.
I'm having trouble understanding what the difference between these two code snippets is:
// out is of type char* of size N*D
// N, D are of type int
for (int i=0; i!=N; i++){
if (i % 1000 == 0){
std::cout << "i=" << i << std::endl;
}
for (int j=0; j!=D; j++) {
out[i*D + j] = 5;
}
}
This code runs fine, even for very big data sets (N=100000, D=30000). From what I understand about pointer arithmetic, this should give the same result:
for (int i=0; i!=N; i++){
if (i % 1000 == 0){
std::cout << "i=" << i << std::endl;
}
char* out2 = &out[i*D];
for (int j=0; j!=D; j++) {
out2[j] = 5;
}
}
However, the latter does not work (it freezes at index 143886 - I think it segfaults, but I'm not 100% sure as I'm not used to developing on windows) for a very big data set and I'm afraid I'm missing something obvious about how pointer arithmetic works. Could it be related to advancing char*?
EDIT: We have now established that the problem was an overflow of the index (i.e. (i*D + j) >= 2^32), so using uint64_t instead of int32_t fixed the problem. What's still unclear to me is why the first above case would run through, while the other one segfaults.
N * D is 3e9; that doesn't fit in a 32 bit int.
When using N as size of array, why use int?
does a negative value of an array has any logical meaning?
what do you mean "doesn't work"?
just think of pointers as addresses in memory and not as 'objects'.
char*
void*
int*
are all pointers to memory addresses, and so are exactly the same, when are defined or passes into a function.
char * a;
int* b = (char*)a;
void* c = (void*)b;
a == b == c;
The difference is that when accessing a, a[i], the value that is retrieved is the next sizeof(*a) bytes from the address a.
And when using ++ to advance a pointer the address that the pointer is set to is advanced by
sizeof(pointer_type) bytes.
Example:
char* a = 1;
a++;
a is now 2.
((int*)a)++;
a is now 6.
Another thing:
char* a = 10;
char* b = a + 10;
&(a[10]) == b
because in the end
a[10] == *((char*)(a + 10))
so there should not be a problem with array sizes in your example, because the two examples are the same.
EDIT
Now note that there is not a negative memory address so accessing an array with a signed negative value will convert the value to positive.
int a = -5;
char* data;
data[a] == data[MAX_INT - 5]
For that reason it might be that (when using sign values as array sizes!) your two examples will actually not get the same result.
Version 1
for (int i=0; i!=N; i++) // i starts at 0 and increments until N. Note: If you ever skip N, it will loop forever. You should do < N or <= N instead
{
if (i % 1000 == 0) // if i is a multiple of 1000
{
std::cout << "i=" << i << std::endl; // print i
}
for (int j=0; j!=D; j++) // same as with i, only j is going to D (same problem, should be < or <=)
{
out[i*D + j] = 5; // this is a way of faking a 2D array by making a large 1D array and doing the math yourself to offset the placement
}
}
Version 2
for (int i=0; i!=N; i++) // same as before
{
if (i % 1000 == 0) // same as before
{
std::cout << "i=" << i << std::endl; // same as before
}
char* out2 = &out[i*D]; // store the location of out[i*D]
for (int j=0; j!=D; j++)
{
out2[j] = 5; // set out[i*D+j] = 5;
}
}
They are doing the same thing, but if out is not large enough, they will both behave in an undefined manner (and likely crash).