I don't understand how I can check if a certain position in an array is been modified or not. Below is an example:
int array[5];
array[2] = 23;
array[4] = 23;
for (int i = 0; i < 5; ++i) {
if (array[i] == ????){
cout << "in array";
} else {
cout << "not in array";
}
}
So I wanted to know how would I get it so the if statement is checking if the item has been modified. So once I becomes 2 it will says it's in array and if not the it should print 'not in array'.
This has to be done using pointers.
This is undefined behavior because array[0] isn't initialized. So when you compare it in your if, what will happen?
You could initialize them all to a value that you consider as "not modified", and check for this value. For instance:
int array[5] = {}; // initializes all elements to the default value for int, which is 0
And then, in your if:
if (array[i] != 0 ) {
If you can't do that because you need the full range of int values, then you can use std::optional instead:
#include <iostream>
#include <optional>
int main() {
std::optional<int> array[5];
array[2] = 23;
array[4] = 0;
for (int i = 0; i < 5; ++i) {
if (array[i]) {
std::cout << "in array" << std::endl;
}
else { std::cout << "not in array" << std::endl; }
}
}
You can't. In C++, it's impossible to determine if an object is uninitialized. Any attempt to read the value of an uninitialized object is Undefined Behavior. They're effectively write-only.
(You might also have a problem with the terminology, or a lack of understanding. array[0] is in the array from the very start, it's just not yet initialized. )
You might use std::map<int, int> values instead. It can truly be empty (values.empty()==true) When you write values[2]=0, a new value is added, and values.size() will be 1 to reflect the new number of elements.
I don't understand how I can check if a certain position in an array is been modified or not.
On x86 you can set a hardware breakpoint on read/write/execute access to a value at a specific address of length of up to 8 bytes. On Linux one API for that is perf_event_open with PERF_TYPE_BREAKPOINT event type. The value of the event counter is how many of interesting accesses to the value at the address have been made.
One option would be using two arrays. A bool array to store the initialization state, and another array to keep desired objects.
(However std::array or std::vector would be better choices than using normal arrays, but that's a different concern)
E.g.
constexpr unsigned int ArrayLen = 5;
bool isInitialized[ArrayLen] = {false};
MyType myArray[ArrayLen]; // In your case `MyType = int`
...
// When setting/resetting update both arrays
void Set(int i, MyType obj)
{
assert(i < ArrayLen);
isInitialized[i] = true;
myArray[i] = std::move(obj);
}
...
// check isInitialized array first before accessing an element
unsigned int targetIndex = 2;
if (isInitialized[targetIndex])
{
auto& obj = myArray[targetIndex];
// use `obj` ...
} else {
// object in `targetIndex` is not initialized
}
In C++17 you can use std::optional so that the initialization state doesn't need to be separately maintained but instead both the state and the object will be bound to a single std::optional object.
Related
After inserting values in dynamic char array, trying to get first value from the top. Method gives me back ² value.
Can you help me with understanding, what I am doing wrong? Here is main method:
char* arr = new char[5]();
arr[0] = 'h';
arr[1] = 'e';
arr[2] = 'l';
arr[3] = 'l';
char result = topValue(arr, 5);
cout << result;
Here is topValue() method:
char topValue(char* stackArr, int stackSize)
{
for (int i = stackSize; i >= 0; i--)
{
std::cout << "In top: " << stackArr[i] << std::endl;
if (stackArr[i] != '\0')
{
return stackArr[i];
}
}
}
In the first iteration of the loop, you access the array outside of its bounds, and the behaviour of the program is undefined.
Note that your function doesn't handle the potential case where all elements are the null terminator character. In such case the function would end without returning a value and the behaviour of the program would be undefined. Either handle that case, or carefully document the pre-condition of the function.
Furthermore, the program leaks memory. I recommend avoiding the use of bare owning pointers.
After inserting values in dynamic char array ...
You aren't inserting values into an array. It isn't possible to insert values into an array. The number of elements in an array is constant.
I am a C++ beginner and my task is as follows:
Define and initialise a single-dimensional integer array. Next, define a pointer that points to the first element in the array and passes the pointer to a function.
Using only pointer variables (and looping constructs), print only the array values that are exact multiples of 7 from start to finish to standard output. The only program output should be the numbers, one per line with no white space.
I have tried:
void print_sevens(int* nums, int length)
{
int array[5] = { 5,8,21,43,70 };
int* ptr = array;
int* num = array;
for (int i = 0; i < length; i++)
{
*num++;
if (num[i] % 7 == 0) {
cout << num[i] << endl;
}
}
}
int main()
{
int array[5] = { 5,8,21,43,70 };
int* ptr = array;
print_sevens(ptr, 5);
}
It compiles but does not output anything.
I am also confused about passing the pointer to a function. Should this be done in the main file or in the function file?
You are creating an additional array in the print_sevens function, which is unnecessary as you already passed the pointer to the first element of the array created in the main()(i.e. array).
Removing that unnecessary array and related codes from the function will make the program run perfectly. (See online)
void print_sevens(int* nums, int length)
{
for (int i = 0; i < length; i++)
{
if (nums[i] % 7 == 0)
std::cout << nums[i] << std::endl;
}
}
and in the main you only need to do the follows, as arrays decay to the pointer pointing to its first element.
int main()
{
int array[5]{ 5,8,21,43,70 };
print_sevens(array, 5);
}
Note that,
num++ increments the pointer, not the underline element it is
pointing to (due to the higher operator precedence of operator++ than operator*). If you meant to increment the element(pointee) you
should have (*num)++.
Secondly, do not practice with using namespace std;. Read more:
Why is "using namespace std;" considered bad practice?
You are modifying the contents of your array when you do *num++.
struct Struct_t {
int Value1;
int Value2;
};
vector<Struct_t> Struct;
Struct.resize(10, Struct_t());
for (int i = 0; i < 10; ++i)
{
Struct[i].Value1 = (i + 10) * 3;
Struct[i].Value2 = (i + 5) * 2;
}
How can I create a pointer to Struct[i]?
What I want to do essentially is something like this, but I'm sure this can be done better:
int value = 6;
Struct_t temp = Struct[value], *s;
s = &temp;
s->Value1 = 42;
s->Value2 = 6;
Main goal is, that I can easily create a pointer to Struct[n] with 1 line/function.
So far, the provided answers are missing the elephant in the room. You could create a pointer to a vector element like so:
(Fault-prone) Code Listing
#include <iostream>
#include <vector>
struct Struct_t {
int Value1;
int Value2;
};
int main(void)
{
std::vector<Struct_t> sVec;
sVec.resize(10, Struct_t());
int count = 0;
for (std::vector<Struct_t>::iterator vIt = sVec.begin(); vIt != sVec.end(); ++vIt)
{
vIt->Value1 = (count + 10) * 3;
vIt->Value2 = (count + 5) * 2;
count++;
}
Struct_t* pStruct = &sVec[5];
std::cout << "sVec[5] = (" << pStruct->Value1 << "," << pStruct->Value2
<< ")" << std::endl;
return 0;
}
Sample Output
sVec[5] = (45,20)
However, vector is not an abstract type you want to use if you will be generating pointers to individual elements of the vector/"array". When the vector needs to be re-sized (shrink or grow), the iterators are invalidated, so your pointers will point to now-freed memory, crashing your program. If you want to have raw pointers directly to vector elements, you want to first:
Use a list rather than a vector.
Possibly use managed pointers to handle reference counts.
Finally, when dealing with template classes like vector, list, hash_table, etc, you should try to get used to using the iterator example I used above, as you don't have to worry about checking for exceptions when using an invalid index (the overloaded [] operators can throw exceptions, unless you replace them with the .at() member function instead for element access).
For a std::vector, &v[i], gives you a pointer to the i'th element. Your sample code becomes:
int value = 6;
Struct_t* s = &Struct[value];
s->Value1 = 42;
s->Value2 = 6;
So the one-liner is Struct_t* s = &Struct[value];
There is nothing wrong with doing this, but like most aspects of C++, you need to understand what you are doing. The above code is perfectly valid and guaranteed by the standard. (Also note that the code in this answer avoids an error in the original code where s was a pointer to a temporary copy and no changes were made to the contents of the Struct vector.)
Yes, resizing Struct will invalidate any pointers made before the resize, and yes, using iterators is often a better technique. But this is a correct and reasonable answer to the original question.
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<>!
I've been trying to erase an element from an array without changing the index order, for instance:
class MyObject
{
int id;
public:
MyObject() { }
void setId( int i ) { id = i; }
void showId() { std::cout << "ID: "<< id << "\n"; }
};
MyObject *myArray;
int main ( )
{
myArray = new myArray[6];
for( int i = 0; i < 6; i++ )
{
myArray[i]->setId(i);
myArray[i]->showId();
}
}
I want to remove myArray[3] without changing the index of the others. e.g:
myArray[0] = ID: 1
myArray[1] = ID: 2
myArray[2] = nothing
myArray[3] = ID: 4
myArray[4] = ID: 5
myArray[5] = ID: 6
I've tried to use use memset(), but it didn't work.
memset(&myArray[3],0,sizeof(MyObject));
There's no such thing as "nothing" in C++ language. Once you have an array, all elements of that array will contain "something". There's no way to make an array element just disappear with keeping all other elements in their original places. You can't create a hole in the array.
All you can do in this case is simply label some element as "deleted" and then later recognize it as such. The element will, of course, continue to exist physically. It is you who'll have to recognize it as "deleted" and ignore it in your further processing. You can either add some bool is_deleted field to your object, or you can use some reserved value of id (like -1) to indicate a deleted element.
In your example with memset you essentially set the id to zero. Is 0 a valid id value? If it is not, then 0 is a good choice to mark a deleted element. In that sense your memset attempt works perfectly fine, as it should. Although I'd recommend doing it by explicitly assigning zero to id, without using memset.
You are calling memset to write a bunch of zeros over the top of an object instance. Do not do this! You may get away with it if your class is a true POD class. You might end up just setting the ID to 0. But maybe there is more to your class that you aren't showing. In anycase, even if it isn't POD, don't use memset like that.
You can either store pointers to object and use the null pointer to indicate there is nothing there. I'd do this with std::vector<MyObject*>. Or you use a sentinel object instance, for example with ID of -1.
The other thing that could be a problem is that you appear to be using 1-based indices. C++ arrays are 0-based, so the first element is myArray[0] and not myArray[1].
Using memset that way is setting all the bytes of that object to 0. This is usually equivalent to setting id to 0, because the memory of an object is the memory of its members (not counting vtables, padding, etc). But don't do that anyway.
One way to do this is to use new and have an array of pointers.
MyObject* myArray[6];
int main ( )
{
for( int i = 0; i < 6; i++ )
{
myArray[i] = new MyObject;
myArray[i]->setId(i);
myArray[i]->showId();
}
}
Then to display them all:
for (int i = 0; i < 6; i++) {
cout << "myArray[" << i << "] = ";
if (myArray[i])
myArray[i]->showId();
else
cout << "nothing" << endl;
}
Then when you want to remove an object, delete it and set its pointer to NULL:
delete myArray
myArray[3] = NULL;
Then when you do anything with one of the objects in myArray, you must check if it is NULL to see if it's a valid object.
Consider boost::optional:
typedef boost::optional<MyObject> MyObjectOpt;
MyObjectOptArr *myArray;
The syntax/usage is a bit different (resembles using pointer):
for (int i = 0; i < 6; ++i) {
if (myArray[i])
cout << "myArray[" << i << "] = " << *(myArray[N]);
else
cout << "nothing" << endl;
}
To unset value do:
myArray[N] = boost::none;