I wrote a function that takes a pointer to an index and checks if it's located within the limits of an array, the function prints the rest of the elements in that array if it's true, and if it's not, it prints "Not in range". The only parameters that this function gets are the array,the length of it and the pointer. The problem I have is that the loop that is responsible for iterating the array and printing the rest of the array also prints garbage values after the last element in the array.
Notes: you can't use any other local variables, only the parameters (array,length,pointer). You also can't use [] operator, only pointer arithmetic.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printAfterX(int* arr, int n, int* x);
int main()
{
int arr[] = { 4, 8, 6, 2, 1, 3, 5, 7, 8, 9, 5 };
printAfterX(arr, 11, arr+6);
return 0;
}
void printAfterX(int* arr, int n, int* x)
{
if (x >= arr && x <= (arr + n)) //this checks if x is in the limits
{
x++;
for (*arr = 0; *arr <= n; *arr++)
{
printf("%d ", *(arr + *x));
}
}
else
{
printf("Not in range ");
}
}
Should be x < (arr + n), not x <= (arr + n). Note that there are a lot of other unchecked conditions in your code. For example, you never check whether or not the element in the array is less than n or not.
If you're not sure whether to use < or <=, you can always do a simple test case in your head: Asssume that your array has two elements, then arr + 0 is valid, arr + 1 is valid, arr + 2 is not. So your n has to be less than 2.
In your for-loop you will always print n numbers, starting from x. Also you set the first element of your array to zero and use it as iterator in for (*arr = 0; *arr <= n; *arr++). As a result you will print numbers that are outside of the range of your array. I would recommend to use another approach on the for-loop like this:
for ( ; x != arr+n; x++)
{
printf("%d ", *x);
}
Based on what you describe as the specification I think there are two problems with this bit of code:
for (*arr = 0; *arr <= n; *arr++)
{
printf("%d ", *(arr + *x));
}
Firstly, that loop is all wrong. You're comparing the current element that arr is pointing at and seeing if it's less than the length of the array. What you should be doing is using n to limit the number of times you go around the loop. You're also making the first element of the array be 0.
Secondly, you're printing random values which could possibly be outside of the array because unless *x is 0, you're not printing some arbitrary value, possibly beyond the end of arr.
Thirdly, your specification says that you want to print everything after the element pointed to by x and you're sort of trying to print everything.
Fixing all three problems you'd end up with code that looks like.
for (x++; x<arr+n; x++)
{
printf("%d ", *arr);
}
and as mentioned elsewhere this if (x >= arr && x <= (arr + n)) should be if (x >= arr && x < (arr + n)) as otherwise you'll be OK if x is one element beyond the length of arr
Related
I created an array called elements_n which has the elements 0 to N-1 where N is 2. The below numbers are the elements of the array called elements_n:
0 1
I have another array called Arr which has the following elements:
0 1 3 1 2 4
If any of the first 3 elements of the array Arr are equal to the first element of elements_n which is 0, I would like to delete that element from the array called Arr. I then repeat the same process for the next 3 elements of the array Arr. So to explain myself better, I will use the following example:
Compare the first 3 elements of array Arr which are 0, 1, 3 to the first element of elements_n which is 0. Since Arr[0] == elements_n[0]. I delete Arr[0] from the array Arr.
Compare the next 3 elements of array Arr which are 1, 2, 4 to the second element of elements_n which is 1. Since Arr[3] == elements_n[1]. I delete Arr[3] from the array Arr. So the elements that should be left in the array Arr are:
1 3 2 4
When I implemented it myself in C programming with the code found below the end result is coming:
1 3 3 2 2 4
Rather than:
1 3 2 4
This is the code I implemented:
#include <stdio.h>
#include <stdlib.h>
#define N 2
int main() {
unsigned *elements_n = malloc(N * sizeof(unsigned));
for (int i = 0; i < N; i++) {
elements_n[i] = i; //Created an array which has the elements 0 to N-1
}
printf("\n");
unsigned Arr[6] = { 0, 1, 3, 1, 2, 4 };
unsigned position_indices[2] = { 3, 3 }; //Moving every 3 elements in the Arr array.
int count = 0;
int index = 0;
unsigned *ptr_Arr = &Arr[0];
do {
for (int i = 0; i < position_indices[count]; i++) {
if (ptr_Arr[i] == elements_n[count]) {
index = i + 1; //Index of the Arr element that has the same value as the element in the array elements_n
for (int j = index - 1; j < position_indices[count] - 1; j++) {
ptr_Arr[j] = ptr_Arr[j + 1];
}
}
}
printf("\n");
ptr_Arr += position_indices[count] - 1;
count++;
} while (count < 2);
for (int i = 0; i < 6; i++) {
printf("%d\t", Arr[i]);
}
printf("\n");
free(elements_n);
return 0;
}
You might try something like this (not tested).
#include <stdio.h>
#include <stdlib.h>
#define N 2
int main()
{
unsigned *elements_n = malloc(N * sizeof(unsigned));
for (int i = 0; i < N; i++)
{
elements_n[i] = i; //Created an array which has the elements 0 to N-1
}
unsigned Arr[6] = { 0, 1, 3, 1, 2, 4 };
int dest_index = 0;
int src_index = 0;
int count = sizeof(Arr)/sizeof(Arr[0]);
for ( ; src_index < count; src_index++)
{
int group = src_index / 3;
if (Arr[src_index] != elements_n[group])
{
Arr[dest_index++] = Arr[src_index];
}
}
for (int i = 0; i < dest_index; i++)
{
printf("%d\t", Arr[i]);
}
printf("\n");
free(elements_n);
return 0;
}
You need to keep track of how many elements you removed from the array.
My solution:
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
#include <string.h>
size_t fancy_delete_3(const int elems[], size_t elemssize, int arr[], size_t arrsize)
{
assert(elems != NULL);
assert(arr != NULL);
assert(arrsize%3 == 0);
assert(elemssize*3 == arrsize);
// we need to count the removed elements, to know how much we need to shift left
size_t removed = 0;
// for each element in elems
for (size_t i = 0; i < elemssize; ++i) {
// check the three correponding elements in arr
for (size_t j = i*3; j < (i+1)*3; ++j) {
assert(j >= removed);
const size_t pos = j - removed;
// if elems[i] matches any of the corresponding element in arr
if (elems[i] == arr[pos]) {
// remove element at position pos
assert(arrsize >= pos + 1);
// I don't think this can ever overflow
memmove(&arr[pos], &arr[pos + 1], (arrsize - pos - 1) * sizeof(int));
++removed;
// array is one element shorter, so we can just decrease the array size
assert(arrsize > 0);
--arrsize;
}
}
}
// we return the new size of the array
return arrsize;
}
#define __arraycount(x) sizeof(x)/sizeof(x[0])
int main()
{
int elements_n[] = {0,1};
int arr[] = {0,1,3, 1,2,4};
size_t newsize = fancy_delete_3(elements_n, __arraycount(elements_n), arr, __arraycount(arr));
printf("arr size=%zu {", newsize);
for (size_t i = 0; i < newsize; ++i)
printf("%d,", arr[i]);
printf("}\n");
return 0;
}
You have several related problems around how you perform deletions. In the first place, it's not clear that you understand that you cannot actually delete anything from a C array. The closest you can come is to overwrite it with something else. Often, pseudo-deletion from an array is implemented by moving each of the elements following the deleted one one position forward, and reducing the logical length of the array.* You seem to have chosen this alternative, but (problem 1) you miss maintaining or updating a logical array length.
Your problem is made a bit more complicated by the fact that you logically subdivide your array into segments, and you seem not to appreciate that your segments are variable-length in that, as described, they shrink when you delete an element. This follows from the fact that deleting an element from one group does not change the assignments of elements to other groups. You do have a mechanism in position_groups that apparently serves to track the sizes of the groups, and in that sense its name seems ill-fitting. In the same way that you need to track and update the logical length of the overall array, you'll need to track and update the lengths of the groups.
Finally, you appear to have an off-by-one error here:
for (int j = index - 1; j < position_indices[count]-1; j++)
that would be clearer if position_indices were better named (see above), but recognizing that what it actually contains is the size of each group, and that index and j represent indices within the group, it follows that the boundary condition for the iteration should instead be just j < position_indices[count]. That's moot, however, because you're going to need a somewhat different approach here anyway.
Suggestion, then:
When you delete an element from a group, move up the entire tail of the array, not just the tail of the group.
In service to that, update both group size and logical array size when you perform a deletion, remembering that that affects also where each subsequent group starts.
When you examine or output the result, remember to disregard array elements past the logical end of the array.
* "Logical array size" means the number of (leading) elements that contain meaningful data. In your case, the logical array size is initially the same as the physical array size, but each time you delete an element (and therefore move up the tail) you reduce the logical size by one.
You never really "deleted" any element, you just shifted-down the
second and third elements from each 3-group. And then, when
printing, you iterated over the whole array.
Arrays are just continuous blocks of memory, so you need a
different strategy. You could traverse the original array with
two indexes, one as the general index counter and other as
the index for the shifted slot. If the current element is
different from the corresponding elements_n item, copy it to
the secondary index and increase it.
In case nothing is equal to the elements_n item, you would just
reassign the array elements to themselves. However, as soon as
one is equal you will be shifting them with the advantage of
keeping track of the new size.
Also, calculating the corresponding elements_n item is a simple
matter of dividing the current index by 3, so you don't even need
an extra variable to that.
#include <stdio.h>
#define N 2
int main()
{
unsigned elements_n[N] = { 0, 1 };
unsigned Arr[N*3] = { 0, 1, 3, 1, 2, 4 };
int i, j;
for (i = 0, j = 0; i < N*3; i++)
if (Arr[i] != elements_n[i/3])
Arr[j++] = Arr[i];
for (i = 0; i < j; i++)
printf(" %d", Arr[i]);
printf("\n");
return 0;
}
so this is the first question ive ever done involving arrays and im a bit confused. The question we are given is:
Write a function named find_elem which takes the following arguments:
~integer elem
~integer array
~int size
with size being the array size, and elem the element you have to find in the array.
If elem is part of the array, return the first position of the element in the array. If elem is not part of the array return -1.
Test Output
int array[] = {4, 2, -6, -1};
printf("%d", find_elem(4, array, 4)); 0
int array[] = {4, 2, -6, -1};
printf("%d", find_elem(-4, array, 4)); -1
The Test column is what the computer automatically reads in and the Output column is what our function should produce.
The following is the code i have written so far, any help is greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int find_elem(int elem, int array[], int size) {
int i;
for (i = 0; i <= size-1; i++) {
if (array[i] == elem) {
printf("%d",i);
}
}
if (array[i] != elem) {
printf("-1");
}
return 0;
}
lets walk through your code, with simple array {1,1,2} and look for element 1:
In the first loop iteration,the condition will be satisfied, the 0 will be printed.
We will then continue for the next element. Again, the condition will be satisfied, and 1 will be printed.
In the next (and last) iteration, the condition will not be satisfied, do nothing will be printed.
Then we go out of the loop.
array, at position 2, is not 1, so , yet again, condition will be satisfied, and -1 will be printed.
To top all this out, the coded will then return constant 0, and not the position...
So you will need to break out of the look, once your element is found, and return that position, of -1 if element is not found.
I do not know who is the author of the assignment but it is evident that he is a very weak programmer.
For starters the order of the parameters should be the following: array, its size, the value that is checked.
As the array is not changed in the function then it should be declared with the qualifier const. In C sizes of objects are calculated as values having the type size_t instead of int. The type int is not large enough to contain sizes of arrays.
If the value is not found in an array then the function should return the size of the array that is the index beyond the valid range of indices.
Take into account that the function should not output any message. It is the caller of the function that decides whether to output a message and which message.
Also you should not use magic numbers like 4.
Nevertheless if to follow the assignment then the function can be defined as it is shown in the demonstrative program.
#include <stdio.h>
int find_elem( int value, const int a[], int n )
{
int i = 0;
while ( i < n && a[i] != value ) i++;
return i == n ? -1 : i;
}
int main(void)
{
int array[] = { 4, 2, -6, -1 };
const int N = sizeof( array ) / sizeof( *array );
int value = 4;
printf( "%d\n", find_elem( value, array, N ) );
value = -4;
printf( "%d\n", find_elem( value, array, N ) );
return 0;
}
Its output is
0
-1
Take into account that neither <stdlib.h> nor <math.h> is required because neither declaration from these headers is used in the program.
thanks for all the help! Combining the tips you guys gave me with some youtube videos I managed to write a very concise function from scratch which works perfectly!
int find_elem(int elem, int array[], int size)
{
for( int i=0 ; i < size; i++)
{
if(array[i] == elem)
{
return i;
}
}
return -1;
}
Thanks again!
See the usage of
return
If I will optimize your code;
for (i = 0; i < size; i++) {
if (array[i] == elem)
return i;
}
in here, "return" will break the loop and return the index value of the array position which is matching with your "elem" value. With breaking the loop, once the program founds that
array[i] == elem
is true, function will be terminated with returning a value. If the "elem" value is not in your array, then program will go out of loop and continutes to execute another code blocks. So that;
for (i = 0; i < size; i++) {
if (array[i] == elem)
return i;
}
return -1;
Returning -1 after the loop ends, will help you to reach your aim for having -1 as a result of not finding "elem" value in your array.
As an addition, for make you understand what was your fault:
1) You looped inside your array, but even if "elem" matches with some value in array, loop continued to look another indices of array.
2) Even "elem" will not match with any value in your array, after your loop ends, you tried to check;
if (array[i] != elem) {
printf("-1");
}
But in this step, "i" was assigned a value which is exceeding the bounds of your array by the for loop. Anyways, even it will not exceed the bounds, your way was wrong to check it.
Need not run for loop upto <= size-1. All elements are covered within 0 to < size. Secondly, in if block(inside for) use a flag variable to determine that ele is found (use a break statement to stop further iterations) or not. Replace (array[i] != elem) with (flag == 0) return 0; i.e. not found.
And note that you are always printing once and returning 0 from function. Hence output will be printed twice. Rather than using printf in find_ele function just return either 1 or 0(Not found).
You can use return as soon as you find element inside loop, it will optimise your code.
Also if loop completed, it means element not found, so no need to check anything else
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int find_elem(int elem, int array[], int size) {
int i;
int flag=0;
for (i = 0; i <= size-1; i++)
{
if (array[i] == elem) {
printf("%d",i);
return i;
}
}
printf("-1");
return -1;
}
In my program to swap array elements randomly, value of j is determined as shown below:
int j = rand() % (i+1);
Instead of (i+1), I tried using i, i+2 which returned valid output.
But for i+3 onward invalid outputs occur,sometimes with an error as:
*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)
Can someone please explain why only a value less than 3 must be added?
Program code is as shown below:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void swap (int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void printArray (int arr[], int n)
{
for (int i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
void randomize ( int arr[], int n )
{
srand ( time(NULL) );
for (int i = n-1; i > 0; i--)
{
int j = rand() % (i+1);
swap(&arr[i], &arr[j]);
}
}
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
int n = sizeof(arr)/ sizeof(arr[0]);
randomize (arr, n);
printArray(arr, n);
return 0;
}
Thank you in advance :)
Instead of (i+1), I tried using i, i+2 which returned valid output. But for i+3 onward invalid outputs occur
For anything greater than i+1 (such as i+2, i+3, etc), the resulting index j from:
int j = rand() % (i+2);
might be, depending on what rand() returns, outside the bounds of the array arr and thus it could result in undefined behaviour.
Can someone please explain why only a value less than 3 must be added?
That's not correct conclusion, either. As said you can't add anything greater 1. It's so happens to "work" with 2 (as with anything undefined behaviour, you just can't rely on it and should avoid it).
You can print the value of j and see for yourself whether it could be outside the bounds of the array.
Your array has n elements in it, and the indexes of those elements range from 0 to n-1.
When you choose a new index with rand() % (i+1), this results in a value from 0 to i. Since i starts at n-1 and goes down to 0, this gives you an index that is in range.
If you use rand() % (i+2) for your random index, the resulting values range from 0 to i+1. On the first iteration of the loop i is equal to n-1, which means you could get the value n as a result, which is out of the range of the array.
At this point, the problem can only occur on the first iteration, and only if the random value is n, so the chance if this happening is about 1 out of 9 runs so it won't happen all the time. If you use i+3, the chance of going out of range doubles on the first iteration of the loop, plus it could happen on the next iteration.
The proper way to generate a random value here is rand() % (i+1). Anything larger than i+1 risks going out of range, and the risk goes up the larger the value is.
Well, I've written a code which basically does:
Asks for array length
User input the array into *p
longestNeg function checks the longest negative sequence.
What it has to do: Return the longest negative sequence with its values.
Problem: in the longestNeg function (throws exception)
if (*arr < 0) {
counter++;
}
Question: Why does it happen?
Question2: Will while (arr < arr + n) work?
Edit3:
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
void longestNeg(int *arr, int n);
int main()
{
int *arr1, n,num = 0,*p;
printf("Please enter the size of the array: ");
scanf("%d", &n);
arr1 = (int*)malloc(n * sizeof(int));
if (arr1 == NULL)
printf("Not enough memory\n");
else printf("Array was allocated!\n" );
for (p = arr1; p < arr1 + n; p++)
{
scanf("%d", p);
}
longestNeg(p - n, n);
free(arr1);
getch();
}
void longestNeg(int *arr, int n)
{
int counter = 0, temp = 0, *p;
for (p = arr; p < arr + n; p++)
{
if (*p < 0) {
counter++;
}
else if (counter > temp) {
temp = counter;
counter = 0;
}
else
counter = 0;
}
if (counter != 0)
for (p = arr; p < arr + counter; p++)
{
printf("%d ", *p);
}
else
printf("No neg numbers.");
}
.....To count the negative numbers, you are incrementing arr past them while checking if they're negative and elapsing counter if so. You then try to print counter numbers from arr, which now points after the negative sequence.
So, just think about it. Imagine that you are a computer. The human has entered 1, 2, -1, -2, -3, -4, 3, 4. You count up - and increment past - the 4 negative numbers. Your pointer arr now points to the penultimate value, 3. The user then asks you to print counter == 4 values from this 3 onwards. But only 2 values are left that belong to the user's allocated region of memory - namely the last pair, 3 and 4.
By trying to use memory that doesn't belong to them, the user invokes undefined behaviour, and the program is perfectly within its rights to do absolutely anything (undefined behaviour) - including segfaulting as it appears to be on your system.
So, stop doing that. Either use a temporary copy of the passed-in pointer arr in your first or both while loops, or do your counting and printing in the same loop. It's really that simple.
Stepping through the problem as though you were the computer is not to be underestimated as a diagnostic tactic that can help you actually think about what you've programmed, if you haven't already.
Two problems: When the loop is done the pointer p points to one beyond the end of the allocated memory. And the second problem is the cause of your problem: You pass a pointer to the pointer to your function which expectes a pointer, leading to undefined behavior.
You should learn to always create function prototype declarations for all your functions, because then the compiler would have been able to catch it and print an error instead of just giving you a warning (which you should have gotten).
I am participating in Harvard's opencourse ware and attempting the homework questions. I wrote (or tried to) write a program in C to sort an array using bubble sort implementation. After I finished it, I tested it with an array of size 5, then 6 then 3 etc. All worked. then, I tried to test it with an array of size 11, and then that's when it started bugging out. The program was written to stop getting numbers for the array after it hits the array size entered by the user. But, when I tested it with array size 11 it would continuously try to get more values from the user, past the size declared. It did that to me consistently for a couple days, then the third day I tried to initialize the array size variable to 0, then all of a sudden it would continue to have the same issues with an array size of 4 or more. I un-did the initialization and it continues to do the same thing for an array size of over 4. I cant figure out why the program would work for some array sizes and not others. I used main to get the array size and values from the keyboard, then I passed it to a function I wrote called sort. Note that this is not homework or anything I need to get credit, It is solely for learning. Any comments will be very much appreciated. Thanks.
/****************************************************************************
* helpers.c
*
* Computer Science 50
* Problem Set 3
*
* Helper functions for Problem Set 3.
***************************************************************************/
#include <cs50.h>
#include <stdio.h>
#include "helpers.h"
void
sort(int values[], int n);
int main(){
printf("Please enter the size of the array \n");
int num = GetInt();
int mystack[num];
for (int z=0; z < num; z++){
mystack[z] = GetInt();
}
sort(mystack, num);
}
/*
* Sorts array of n values.
*/
void
sort(int values[], int n)
{
// this is a bubble sort implementation
bool swapped = false; // initialize variable to check if swap was made
for (int i=0; i < (n-1);){ // loops through all array values
if (values[i + 1] > values [i]){ // checks the neighbor to see if it's bigger
i++; // if bigger do nothing except to move to the next value in the array
}
else{ // if neighbor is not bigger then out of order and needs sorting
int temp = values[i]; // store current array value in temp variable for swapping purposes
values[i] = values[i+1]; //swap with neighbor
values[i+1] = temp; // swap neighbor to current array value
swapped = true; // keep track that swap was made
i++;
}
// if we are at the end of array and swap was made then go back to beginning
// and start process again.
if((i == (n-1) && (swapped == true))){
i = 0;
swapped = false;
}
// if we are at the end and swap was not made then array must be in order so print it
if((i == (n-1) && (swapped == false))){
for (int y =0; y < n; y++){
printf("%d", values[y]);
}
// exit program
break;
}
} // end for
// return;
}
You can easily use 2 nested for loops :
int i, j, temp ;
for ( i = 0 ; i < n - 1 ; i++ )
{
for ( j = 0 ; j <= n - 2 - i ; j++ )
{
if ( arr[j] > arr[j + 1] )
{
temp = arr[j] ;
arr[j] = arr[j + 1] ;
arr[j + 1] = temp ;
}
}
}
also you should now it's a c++ code not a c, because c doesn't have something like :
int mystack[num];
and you should enter a number when you're creating an array and you can't use a variable (like "int num" in your code). This is in C, but in C++ you're doing right.
The first thing to do when debugging a problem like this is ensure that the computer is seeing the data you think it should be seeing. You do that by printing out the data as it is entered. You're having trouble with the inputs; print out what the computer is seeing:
static void dump_array(FILE *fp, const char *tag, const int *array, int size)
{
fprintf(fp, "Array %s (%d items)\n", tag, size);
for (int i = 0; i < size; i++)
fprintf(fp, " %d: %d\n", i, array[i]);
}
int main(void)
{
printf("Please enter the size of the array \n");
int num = GetInt();
printf("num = %d\n", num);
int mystack[num];
for (int z = 0; z < num; z++)
{
mystack[z] = GetInt();
printf("%d: %d\n", z, mystack[z]);
}
dump_array(stdout, "Before", mystack, num);
sort(mystack, num);
dump_array(stdout, "After", mystack, num);
}
This will give you direct indications of what is being entered as it is entered, which will probably help you recognize what is going wrong. Printing out inputs is a very basic debugging technique.
Also, stylistically, having a function that should be called sort_array_and_print() suggests that you do not have the correct division of labour; the sort code should sort, and a separate function (like the dump_array() function I showed) should be used for printing an array.
As it turns out the reason why it was doing this is because when comparing an array's neighbor to itself as in:
if (values[i + 1] > values [i])
The fact that I was just checking that it is greater than, without checking if it is '=' then it was causing it to behave undesirably. So if the array is for example [1, 1, 5, 2, 6, 8] then by 1 being next to a 1, my program did not account for this behavior and acted the way it did.