Array address in c++ - c++

I have some code like this :
int n;
cin >> n;
int array[n];
for (int i = 0; i < n; ++i) {
cin >> array[i];
}
int tmp[n - 1];
tmp[0] = 1;
With input : 1 10 I found that the value of array[0] was changed , instead of 10 it has the same with tmp[0].
Then I realized with that input the length of tmp[] became zero. So I print the address of array[] and tmp[] with:
printf("%d\n %d\n", array, tmp);
and found they had the same address.
I want to figure out what will happen if an array has a length of 0; so I tried this:
int array[1];
array[0] = 10;
int tmp[0];
tmp[0] = 1;
address:
array[]: 1363909056
tmp[] : 1363909052
It looks just like the previous code (except the input part). But tmp[0] and array[0] has different values and address now.
And I'm really confused that tmp has smaller address then array.
So my question is:
What will happen if I declare an array of length zero?
Why these two codes works different? (they look the same to me :) )

This is called "undefined behavior". After declaring, in your case
int tmp[0];
The next thing that happens is:
tmp[0]=1;
Since tmp[0] does not exist, this is undefined behavior. Your problem is not that the array was declared with size 0 (that's not exactly kosher on its own merits, but is not the issue here), but the undefined behavior as a result of overwriting memory past the end of the array.

Related

What's being compared to the last element of the array?

There's a behavior that I don't understand, the c variable is supposed to increase by one every time an element of the array isn't equal to the one next to it, but there's one increment that's done automatically which increases c by one. I think this is because the last element of the array is compared to something which isn't equal to it. Why is this happening? Or if I'm right what's the thing that the last element is compared to?
#include <iostream>
int main() {
int n, c = 0;
std::cin >> n;
std::string s[n];
for (int i = 0; i < n; i++) {
std::cin >> s[i];
}
for (int i = 0; i < n; i++) {
if (s[i] != s[i+1]) {
c++;
}
}
std::cout << c;
}
std::string s[n]; is creating what is known as a "Variable-Length Array", which is NOT part of standard C++, but is supported as an extension by some compilers. Don't rely on this. Use std::vector instead for a dynamic-length array whose length is not known until runtime.
But, more importantly, your 2nd loop has undefined behavior. The valid indexes for the s[] array's elements are 0..n-1, so on that loop's last iteration, s[i] accesses the last string in the array, and s[i+1] accesses out of bounds, so the value that s[i] is compared to is indeterminate (if the code doesn't just crash outright from accessing invalid memory).
s[s.length()] == ‘\0’
From here: https://www.cplusplus.com/reference/string/string/operator%5B%5D/
“If pos is equal to the string length, the function returns a reference to the null character that follows the last character in the string (which should not be modified).”

In this Fibonacci function which works, doesn't it pass the number of elements that can be stored in the array? [duplicate]

This question already has answers here:
Accessing an array out of bounds gives no error, why?
(18 answers)
Closed 3 years ago.
This is my code and it works. For example, when n=5, it returns 5. Since n=5, and defining arr[0] = 0, isn't there only four more spaces left to store the elements from arr[1] to arr[4]?
However, it seems like 6 elements(from arr[0] to arr[5]) could be stored and I do not know how.
int fibonacci(int n) {
int i;
int arr[n];
arr[0] = 0;
for(i=1; i<=n; i++)
{
if(i==1)
{
arr[i] = 1;
}
else
{
arr[i] = arr[i-2] + arr[i-1];
}
}
return arr[n];
}
This is undefined behaviour.
Behind the scenes
What's going on behind the scenes is that 5 ints are allocated on the stack. Lets say they're put at address 0x20 to 0x30. The array notation [] is really syntax sugar for using pointers. This means that arr[0] really is a pointer to 0x20. Your array in this case translates to the following addresses (because sizeof(int) = 4):
arr[0] = (arr+0) = 0x20
arr[1] = (arr+1) = 0x24
arr[2] = (arr+2) = 0x28
arr[3] = (arr+3) = 0x2C
arr[4] = (arr+4) = 0x30
This is all fine and good, you're operating on allocated memory. What happens when you try to write to index 5? Well, the same thing, basically:
arr[5]= (arr+5) = 0x34.
It's still just a pointer to an address that you want to write to. The problem is, however, that you haven't told anyone that you intend to write to that address - the memory has not been set aside for you.
If it has not been set aside for anything else, this will likely turn out alright - as you observe.
However if it has it can turn into all sorts of strange behavior depending on what it was used for. Maybe it has been set aside and is just not used yet, maybe it has been used but is simply overwritten and will not be checked again. The point is we don't know! Therefore it is dangerous and undefined.
The reason why it even works in the first place, is that - again - it is just dereferencing a pointer. And dereferencing a pointer should work, as you're trusted to know more that the compiler. It may warn you that you probably shouldn't do this, but it's not an error per se.
What you should do instead
When working with variable length arrays in C++, one should use the modern tools available since C++11. In this scenario, it's advisable to use std::vector instead. If you use the at function rather than [] it checks whether the index is inside the bounds.
Its unexpected behavior, even warn by C++ documents, maybe they removed out-boundary checking. Not only that, you even assign to it. So better to be under range.
#include <iostream>
using namespace std;
int main(){
int i, n = 5;
int arr[n];
arr[0] = 0;
arr[1] = 1;
for(i=2; i<n; i++){
arr[i] = arr[i-2] + arr[i-1];
}
arr[8]=99; //assigning out of range
//accessing out of range
for(i=0;i<20;i++){
cout<<arr[i]<<" ";
}
}
#OUT: 0 1 1 2 3 0 211951624 1 99 32766 -484579280 32766 -1740650656 32767 -484579408 32766 5 0 5 0
You are facing issues with the int array. int arr[n]; is not valid C++ code if n is not fix at compile time. You can rewrite your code with the help of std::vector as
int fibonacci(int n) {
std::vector<int> arr(n);
arr[0] = 0;
for(int i=1; i<=n; i++)
{
if(i==1)
{
arr[i] = 1;
}
else
{
arr[i] = arr[i-2] + arr[i-1];
}
}
return arr[n];
}
Comments:
Your code will use a lot of memory for large Fibonacci numbers, since you store the entire series. This is superfluous, since only have to store the last two entries of the Fibonacci series.
You don't have to loop over n in order to calculate the Fibonacci number. The Moivre-Binet formula gives a much quicker way of calculating these.
for(i=1; i<=n; i++)
the for loop wil run if i is less than or equal to n, which means that when n = 5, it will still run.

How to initialize a very long array?

I am just trying to initialize a huge array. My code is given below:
#include<iostream>
using namespace std;
int main()
{
int T;
cin >> T;
while (T--)
{
int d;
cin >> d;
int arr[d + 1];
for (int i = 0; i <= d; i++)
arr[i] = 0;
}
return 0;
}
Now when I input
1 502334160
then I got error Runtime Error - SIGSEGV.
I want to know how to initialize this type of array.
The array may be too big to fit in your program's stack address space. If you allocate the array on the heap you should be fine.
int* arr = new int[d + 1];
But remember that this will require you to delete[] the array. A better solution would be to use std::vector<int> and resize it to d + 1 elements.
First: Variable length arrays (VLA) are illegal in C++. It might be an extension (as it is in gcc), but it won't build on all compilers.
Second: You can initialize an array with brace initialization. If you don't specify all elements, the others will get default value of 0 (in case of int). So:
int arr[SIZE] {} //specify 0 elements -> all initialized to value 0
Third thing: you allocate your array on stack, so when you create an array of length 1502334160 than it's stack overflow. This amount of ints (assuming 4 bytes each) is almost 6GB of memory while stack is usually 1-2MB.

Store int value into char* - C++?

I have allocated a block of memory as (char *), in which I want to be able to store an integer.
char * arr = new char[50];
int num = 9;
for(int i = 0; i < sizeof(int); i++)
{
*((int *)arr) = arr[i];
}
memcpy(&arr, &num, sizeof(num));
cout<<"Contents of arr: "<<arr<<endl;
I seem to be getting a segmentation fault whenever I compile however. How can I fix this? Thank you!
The for loop is unnecessary. I'm not sure what it is trying to accomplish. The memcpy is ok except that you're taking the address of arr which is already a pointer. This will work:
char * arr = new char[50];
int num = 9;
memcpy(arr, &num, sizeof(num));
cout<<"Contents of arr: "<< ((int *)arr) <<endl;
Perhaps your for loop was trying to do this:
char * arr = new char[50];
int num = 9;
*((int *)arr) = num;
cout<<"Contents of arr: "<< ((int *)arr) << endl;
That would be ok, too.
Edit: The contents of the array are not printable directly, at least not with any meaning (and may crash because of no zero termination). Assuming you want it to look like an integer, I've edited the code above. C++ purists will probably object to using a C style cast instead of reinterpret_cast<>, but that's a separate issue.

After passing by reference to modify an array, why it stays the same?

I am practicing pointers by creating a Big Number struct, which has numDigits (number of digits) and digits (contents of the big number).
I create a function called removeZero(). After passing the integer array and the size n into it, because of passing by reference, I am supposed to cut down the leading zeros for my input. It works, when the integer array is in main function. However, when I pass an array that is in readDigits, it does not return with a non-leading-zero version. Why? How to fix it?
struct BigNum{
int numDigits;
int *digits; //the content of the big num
};
int main(){
int A[] = {0,0,0,0,0,0,1,2,3};
int n=9;
int *B=A;
//removeZero(A,n); If I use this, it cannot compile
//error: invalid initialization of non-const reference of type ‘int*&’ from an rvalue of type ‘int*’
removeZero(B,n);
for (int i=0; i<n; i++){
std::cout << *(B+i) << std::endl;
}
BigNum *num = readDigits();
return 0;
}
BigNum* readDigits(){
std::string digits;
std::cout << "Input a big number:" << std::endl;
std::cin >> digits;
//resultPt in heap or in stack?
int *resultPt = new int[digits.length()]; //in heap
int n = digits.length();
toInt(digits,resultPt);
removeZero(resultPt,n);
//Output the leading zeros, why?
for (int i=0; i<n; i++){
std::cout << *(resultPt +i) << std::endl;
}
BigNum *numPtr = new BigNum();
numPtr->numDigits = n;
numPtr->digits = resultPt;
return numPtr;
}
void toInt(std::string& str, int *result){
for (int i=0;i<str.length() ;i++ ){
result[str.length()-i-1] = (int)(str[i]-'0');
}
}
void removeZero(int* &A,int& n){
int i=0;
while (A[i]==0){
i++;
}
A=A+i; //memory leak?
n=n-i;
}
bool areDigits(std::string num){
for(int i=0;i<num.length();i++){
if(num[i]<'0' || num[i] >'9'){
return false;
}
}
return true;
}
Note that an array and a pointer are two different things. When you pass an array to a function, it degrades to a const pointer. This means that you cannot pass an array to a function which expects a int*&.
It could be the problem of scope of numPtr.numPtr is local variable of function readDigits(). Instead of returning pointer. Pass num to readDigits().
The signature of your removeZero function is:
void removeZero(int* &A,int& n);
That means the forst parameter is a reference of a pointer but the pointer is a non-const one, and you cannot therefore pass an array there, as array is a constant pointer (starting address cannot be changed).
In fact you are changing the starting address within removeZero.
With removeZero, the while loop shopuld be changed from:
while (A[i]==0){
to:
while ((A[i]==0) && (i<n)){
You have a logic error in toInt.
void toInt(std::string& str, int *result){
for (int i=0;i<str.length() ;i++ ){
// This stores the digits in the reverse order.
result[str.length()-i-1] = (int)(str[i]-'0');
}
}
That line should be
result[i] = (int)(str[i]-'0');
If you intend to keep the digits in reverse order, then removeZero has to be changed keeping that in mind.
`
When you say
int *B=A;
you are just creating a pointer to point to the same memory
of the Array A. Just by incrementing the pointer(*B) within the function
removeZero
A=A+i;
you are not deleting anything but you are just incrementing the pointer(*B)
to point to subsequent memory location within the array.
The original array memory pointed to by A remains the same, since you
have not changed any contents of the array, but you have just
incremented a pointer pointing to the same memory location as that of the array.
Also there are so many problems, like "Debasish Jana" mentioned,
you have to change your while loop. ""Code-Apprentice" gave you the reason for your
compilation error when you uncomment your commented code.
Also within "removeZero" you are incrementing A by i instead of "1" like
A=A+1;
This is one of the reason for the strange behavior you experience
Even after changing all this, you cannot see your array getting changed,
since you are not modifying any of the contents of your array.
If you really want to delete the contents of the array and change it dynamically,
you have to go for Vector<>. With static memory allocation you cannot cut the
array size short by removing some elements here and there. Learn Vector<>!