It is safe to use i+1 in O(n) searching? - c++

I'm asking myself if it is safe to use i+1 to check if the next number is the same as current... Example :
int search(int el, int* a, int n) {
if(a == NULL && n<0)
{
return NULL;
}
for(int i=0; i<n; i++)
{
if((a[i] == el )&& (a[i+1] != el)) // here I check next element
{
return i; // if I find it, return a position.
}
}
return -1; // else return -1
}
If we have an array with length 4, then a[i+1] will be passed an array length, but program will still work.

No, accessing elements out of bounds is Undefined Behavior.
Your program may "seem" to work, but you cannot expect anything out of it. It could work on your machine, and crash on another one. Or it could work on all machines now, but not tomorrow. You should check if the index is out-of-bounds before using the subscript operator.
You may consider changing your cycle so that it never accesses out-of-bounds elements:
for (int i = 0; i < n - 1; i++)
// ^^^^^
Then, you would have to take care of the last element in the array separately, as a special case.

That's not correct, when i reaches its last value (n-1) you check the value of a nonexistent element (the C standard allows you to have a pointer to one-after-last element, but not to dereference it).
You can fix your code like this:
if((a[i] == el ) && ((i == n-1) || (a[i+1] != el)))

If n is the last element in the array, then i + 1 is safe in this case. If n is the number of elements in the array, i + 1 may appear to work most of the time, but it is not safe.
In that case, you're accessing an element outside the bounds of the array, which may do anything from giving you incorrect results to crashing your program. Most of the time it will appear to work, though, making the problem very hard to debug when it happens.

It is not clear to me what you're asking. Even if array access is expensive, accessing both a[i] and a[i+1] remains of O(N) complexity. What you can't do is adding complexity that's based on i (for example an additional loop from 0 to i), or modifying i (for example decrementing it based on some condition).
The problem, as others have already pointed out, is that the last element is compared to a nonexistent datum: either you'll get an error and a possible crash, or the program will appear to be working - and actually work most of the time - until the time where that unknown and possibly random last-and-one item will trigger the comparison, and yield an unexpected result.
You should check that the array size is at least 1 (that ought to be a special case anyway, can't run a compare on a single element!) and then loop only up to n-1. Or you could save the previous value in a temporary variable; depending on the platform, this will be a (possibly much faster) register, or a (possibly much slower) stack location. In most cases I'd just state my intention of comparing with the next element, as you did, and let the compiler sort it out.

No.
int main(void)
{
char pumpkin[8];
int a[4];
int i, p;
a[0] = 3760;
a[1] = 100001;
a[2] = 595959;
a[3] = 1886221680;
pumpkin[0] = 'p';
pumpkin[1] = 'u';
pumpkin[2] = 'm';
pumpkin[3] = 'p';
for (i = 0; i < 4; i++) {
p = search(a[i], a, 4);
if (p >= 0)
printf("Found it at position %d: %d.\n", p, a[i]);
else
printf("Value not found.\n");
}
return 0;
}
In my machine:
$ gcc -std=c11 -o boundserror boundserror.c
$ ./boundserror
Found it at position 0: 3760.
Found it at position 1: 100001.
Found it at position 2: 595959.
Value not found.
What happened ? Compiler wrote value 1886221680 both in a[3] and where a[4] would be if it existed. About the program working on your machine: read about the works on my machine concept.
http://www.codinghorror.com/blog/2007/03/the-works-on-my-machine-certification-program.html

Related

C++ time limit exceeded when it doesn't even execute the function

While I was solving a problem in LeetCode, I found something very strange.
I have this line which I assume gives me a time limit exceeded error:
s.erase(i-k, k);
when I comment(//) this line, it doesn't show me time exceed error, but the strange part was, it has never executed even when i didn't comment it.
below is the entire code.
and Here is the problem link.
class Solution {
public:
string removeDuplicates(string s, int k) {
char prev = s[0];
int cnt = 1;
cnt = 1;
for(int i = 1; i < s.size() + 1; i++){
if(s[i] == prev){
cnt++;
} else {
if(cnt == k){
// when input is "abcd" it never comes to this scope
// which is impossible to run erase function.
s.erase(i-k, k);
i = 0;
}
if(i >= s.size()) break;
cnt = 1;
prev = s[i];
}
}
return s;
}
};
When Input is "abcd", it never even go to the if scope where 'erase' function is in.
Although 'erase' function never run, it still affect on the time complexity, and I can't get the reason.
Does anyone can explain this? or is this just problem of LeetCode?
Many online contest servers report Time Exceeding when program encounters critical error (coding bug) and/or crashes.
For example error of reading out of bounds of array. Or dereferencing bad (junk) pointers.
Why Time Exceeded. Because with critical error program can hang up and/or crash. Meaning it also doesn't deliver result in time.
So I think you have to debug your program to find all coding errors, not spending your time optimizing algorithm.
Regarding this line s.erase(i-k, k); - it may crash/hang-up when i < k, then you have negative value, which is not allowed by .erase() method. When you get for example i - k equal to -1 then size_t type (type of first argument of erase) will overflow (wrap around) to value 18446744073709551615 which is defnitely out of bounds, and out of memory border, hence your program may crash and/or hang. Also erase crashes when there is too many chars deleted, i.e. for erase s.erase(a, b) you have to watch that a + b <= s.size(), it is not controlled by erase function.
See documentation of erase method, and don't put negative values as arguments to this method. Check that your algorithm never has negative value i.e. never i < k when calling s.erase(i-k, k);, also never i-k + k > s.size(). To make sure there is no program crash you may do following:
int start = std::min(std::max(0, i-k), int(s.size()));
int num = std::min(k, std::max(0, int(s.size()) - start));
s.erase(start, num);

trying to write heapify algorithm - segmentation fault

I'm ultimately trying to use heapsort to alphabetically sort words that have been read in. I've never done heaps before so I'm trying to follow along with my book. I'm using cin to store the words into a dynamically allocated array, as number of words is unknown ahead of time. From separate code I know it is being read in and the array is getting larger correctly. Then I'm trying to heapify this array, but I keep getting a segmentation fault as I'm new to programming, I can't determine how to trace this back to what I did wrong. This is my heapify code:
void Heap::make(){
//make a heap from wordArray
//r = last non-leaf
for(int r = size/2; r > 1; r--){
int c = 2 * r; //location of left child
while(r <= size){ //size is a data member of Heap
//if r has 2 children and right is larger, make c the right child
if((c < size) && (wordArray[c] < wordArray[c+1])){
c++;
}
//fix if parent failed heap-order condition
if(wordArray[r] < wordArray[c]){
swap(wordArray[r], wordArray[c]);
r = c; //check that it didn't get messed up at c
c = 2 * c;
}
else{
break; //heap-order condition holds so stop
}
}
}
}
from playing around with couts I can determine that the program works until the if(wordArray[r] < wordArray[c]) part. The elements of wordArray are stings, and the comparators work correctly from outside testing. Is this something to do with the array being dynamic or something? I'm confused as to what I'm doing wrong here.
You are reading out of bounds. When you check:
if((c < size)
where c is the last element, you read out of bounds here:
if((c < size) && (wordArray[c] < wordArray[c+1])){
^
The check should be:
if((c+1 < size)
And yet another problem is here:
while(r <= size)
where r is used in the code when it is clearly out of bounds if it r == size.
For arrays of size, n, their elements go from 0 to n-1, so accessing nth element is undefined behavior.
You can access the nth element of an array by it's it's n-1 line arr[n-1];//this is the nth element
Segmentation fault occur here in your code
(wordArray[c] < wordArray[c+1]) // try to modify this.
Lets assume the size = 6
Whwn for() loop will run for the first time, c = 2*6 means 6, and you are accessing the arr[6] and arr[6+1] both are not valid. Array index starts from zero instead of one.

adding dynamic arrays and removing trailing 0's

I am trying to implement this function to add two dynamic a
rrays, however when I implement this into my main it completely crashes, I have no idea why...
I cannot understand why the program shuts down except the exit code on scite says exit code 255. But that is not helpful. Any idea what the problem may be?
For one:
for (int k=0; k<=max; k++)
This goes out of range. Instead allocate memory for [max+1] elements, since there shall be max+1 terms in the polynomial.
sum = new int[ max + 1 ];
Also, the j loop should start from max.
for (j=max; j>0 && sum[j]==0; --j);
You have a typo on this line:
for (j=max-1; j>0 && sum[j]==0; --j);
^here
The next statement int *tmp=sum; does not get executed.
Also the for loop should probably be
for (j=max-1; j>=0 && sum[j]==0; --j)
^ //don't forget the last member
A couple of nice things about C++ is all the standard containers (like std::vector) and standard algorithms available. For example you could use vectors and backwards iterators and std::find_if_not to find the last non-zero value.
Like
// Create a vector of a specific size, and initialize it
std::vector<int> sum(std::max(a->degree, b->degree), 0);
// Fill it up...
// Find the last non-zero value
auto last_non_zero = std::find_if_not(sum.rbegin(), sum.rend(),
[](const int& value){ return value == 0; });
if (last_non_zero == sum.rbegin())
{
// No zeroes found
}
else if (last_non_zero == sum.rend())
{
// All of it was zero
sum.clear();
}
else
{
std::vector<int> temp(last_non_zero, sum.rend())
std::reverse(temp); // Because the `temp` vector is reversed
sum = temp;
}
After this the vector sum should have been stripped of trailing zeroes.

Recursive call segmentation fault issue

quick question again.
I'm creating a recursive function that will look for elements in a array of "source" rules and apply those rules to an "target array" of rules if the "source" rule type is the same as the target character. Furthermore the function checks to see if the target character is in an array of symbols or not and adds it if it is not (and throws a few flags on the newly applied rule as well). This is all driven by a recursive call that uses a counter to determine how many iterations have passed and is used to determine the spot in the target array the new rule should be applied, so we don't overwrite.
I've put in a little debugging code to show the results too.
Here's the function itself:
//Recursively tack on any non terminal pointed elements
int recursiveTack(rule * inrule[], char target, rule * targetrule[],
int counter, char symbols[])
{
printf("Got into recursiveTack\n");
printf("target is %c\n", target);
printf("counter is %d", counter);
for (int k = 0; k < sizeof(inrule); k++)
{
if (inrule[k]->type == target)
{
//doublecheck to see if we're trying to overwrite
if (targetrule[counter]->used = true)
{
counter++;
}
targetrule[counter]->head = inrule[k]->head;
targetrule[counter]->type = inrule[k]->type;
targetrule[counter]->used = true;
//Check to see if the elements are new to the symbols table and need to be added
if (!contains(returnGotoChar(targetrule[counter]), symbols))
{
//If not then add the new symbol
addChar(returnGotoChar(targetrule[counter]), symbols);
//Also set the goto status of the rule
targetrule[counter]->needsGoto = true;
//Also set the rule's currentGotoChar
targetrule[counter]->currentGotoChar = returnGotoChar(
targetrule[counter]);
}
counter++;
//recursivly add elements from non terminal nodes
if (isNonTerm(targetrule[counter]))
{
char newTarget = returnGotoChar(targetrule[counter]);
counter = recursiveTack(inrule, newTarget, targetrule, counter,
symbols);
}
}
}
//return how many elements we've added
return counter;
}
Here's the call:
if(isNonTerm(I[i+first][second]))
{
printf("Confirmed non termainal\n");
printf("Second being passed: %d\n", second);
//Adds each nonterminal rule to the rules for the I[i+first] array
second = recursiveTack(I[i], targetSymbol, I[i+first], second, symbols[first]);
}
All the arrays being passed in have been initialized prior to this point.
However, the output I get indicates that the recursion is getting killed somewhere before it gets off the ground.
Output:
Second being passed: 0
Confirmed non termainal
Got into recursiveTack
target is E
Segmentation fault
Any help would be great, I've got the rest of the program available too if needs be it's around 700 lines including comments though. I'm pretty sure this is just another case of missing something simple, but let me know what you think.
for(int k = 0; k < sizeof(inrule); k++)
sizeof(inrule) is going to return the size of a pointer type (4 or 8). Probably not what you want. You need to pass the size of the arrays as parameters as well, if you are going to use these types of structures.
It would be better to use Standard Library containers like std::vector, though.
if(targetrule[counter]->used = true){
counter++;
}
// what is the guarantee that targetrule[counter] is actually valid? could you do a printf debug before and after it?
The biggest thing I see here is:
for(int k = 0; k < sizeof(inrule); k++)
This isn't going to do what you think. inrule is an array of pointers, so sizeof(inrule) is going to be the number of elements * sizeof(rule*). This could very quickly lead to running off the end of your array.
try changing that to:
for (int k = 0; k < sizeof(inrule) / sizeof(rule*); ++k)
Something else you might consider is an fflush(stdout); after your print statements. You're crashing while some output is still buffered so it's likely hiding where your crash is happening.
EDIT:
That won't work. If you had a function that did something like:
int x[10];
for (int i = 0; i < sizeof(x) / sizeof(int); ++i) ...
It would work, but on the other side of the function call, the type degrades to int*, and sizeof(int*) is not the same as sizeof(int[10]). You either need to pass the size, or ... better yet, use vectors instead of arrays.

Vector push_back in while and for loops returns SIGABRT signal (signal 6) (C++)

I'm making a C++ game which requires me to initialize 36 numbers into a vector. You can't initialize a vector with an initializer list, so I've created a while loop to initialize it faster. I want to make it push back 4 of each number from 2 to 10, so I'm using an int named fourth to check if the number of the loop is a multiple of 4. If it is, it changes the number pushed back to the next number up. When I run it, though, I get SIGABRT. It must be a problem with fourth, though, because when I took it out, it didn't give the signal.
Here's the program:
for (int i; i < 36;) {
int fourth = 0;
fourth++;
fourth%=4;
vec.push_back(i);
if (fourth == 0) {
i++;
}
}
Please help!
You do not initialize i. Use for (int i = 0; i<36;). Also, a new variable forth is allocated on each iteration of the loop body. Thus the test fourth==0 will always yield false.
I want to make it push back 4 of each number from 2 to 10
I would use the most straight forward approach:
for (int value = 2; value <= 10; ++value)
{
for (int count = 0; count < 4; ++count)
{
vec.push_back(value);
}
}
The only optimization I would do is making sure that the capacity of the vector is sufficient before entering the loop. I would leave other optimizations to the compiler. My guess is, what you gain by omitting the inner loop, you lose by frequent modulo division.
You did not initialize i, and you are resetting fourth in every iteration. Also, with your for loop condition, I do not think it will do what you want.
I think this should work:
int fourth = 0;
for (int i = 2; i<=10;) {
fourth++;
fourth%=4;
vec.push_back(i);
if (fourth==0) {
i++;
}
}
I've been able to create a static array declaration and pass that array into the vector at initialization without issue. Pretty clean too:
const int initialValues[36] = {0,1,2...,35};
std::vector foo(initialValues);
Works with constants, but haven't tried it with non const arrays.