Weird behavior with C array - arrays

I have two arrays A and B both with the same elements { 1, 2, 3, 4 } but after doing A[B[i]] = A[i] + 1 array B is getting populated with different number but in reality it should be unchanged.
#include <stdio.h>
void arrayPrint(int *arr, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int A[4] = { 1, 2, 3, 4 };
int B[4] = { 1, 2, 3, 4 };
int n = 3;
printf("Before \n");
printf("Array A \n");
arrayPrint(A, 4);
printf("Array B \n");
arrayPrint(B, 4);
for (int i = 0; i <= n; i++) {
if (A[i] == B[i]) {
A[B[i]] = A[i] + 1;
}
}
printf("\nAfter \n");
printf("Array A \n");
arrayPrint(A, 4);
printf("Array B \n");
arrayPrint(B, 4);
return 0;
}
Output is:
Before
Array A
1 2 3 4
Array B
1 2 3 4
After
Array A
1 2 3 4
Array B
5 2 3 4
but it should be:
Before
Array A
1 2 3 4
Array B
1 2 3 4
After
Array A
1 2 3 4
Array B
1 2 3 4

For B[i] equal to 4 the expression A[B[i]] access memory beyond the array A because the valid range of indices for the array A is [0, 3].
So it seems the compiler placed the array B at once after the array A and the first element of the array B was changed in this statement
A[B[i]] = A[i] + 1;
for i equal to 3.
Instead of your for loop
for (int i = 0; i <= n; i++) {
if (A[i] == B[i]) {
A[B[i]] = A[i] + 1;
}
}
you could write for example
for (int i = 0; i <= n; i++) {
if ( i != 3 && A[i] == B[i]) {
A[B[i]] = A[i] + 1;
}
}
Or more precisely
const size_t N = sizeof( A ) / sizeof( *A );
for (int i = 0; i <= n; i++) {
if ( i != N - 1 && A[i] == B[i]) {
A[B[i]] = A[i] + 1;
}
}

In last iteration of the for loop, i has the value 3, so A[B[i]] = A[i] + 1; evaluates as A[4] = A[3] + 1;.
Storing anything into A[4] has undefined behavior. What you observe is consistent with the array B being placed in memory immediately after array A but this is by no means guaranteed by the C Standard. The behavior is just undefined and anything can happen.

Related

dealing with dups in end of the array

This is the task I have got:
I need to write a function (not recursive) which has two parameters.
An array of integers.
An integer representing the size of the array.
The function will move the duplicates to an end of the array.
And will give the size of the different digits.
Example:
5 , 2 , 4 , 5 , 6 , 7 , 2, n = 7
we will get back 5 , 2 , 4 , 6 , 7 , 5 , 2 and 5
We must keep the original sort as it is (which means like in example 5 must)
It does not matter how we sort the duplicates ones but just keep the sort for the original array as it is)
The function has to print the number of different digits (like in example 5)
The the input range of numbers in array [-n,n]
I can only use 1 additional array for help.
It has to be O(n)
I tried it so many times and feel like am missing something. Would appreciate any advice/suggestions.
int moveDup(int* arr, int n)
{
int* C = (int*)calloc(n * 2 + 1, sizeof(int));
assert(C);
/*int* count = C + n;*/
int *D = arr[0];
int value = 0, count = 0;
for (int i = 0; i < n; i++)
{
value = arr[i];
if (C[value + n] == 0)
{
*D = arr[i];
D++;
count++;
}
C[value + n] = C[value + n] + 1;
}
while (1 < C[value + n])
{
*D = i;
D++;
C[value + n]--;
}
free(C);
return count;
}
This algorithm will produce the required results in O(n) arithmetic complexity:
Input is an array A with n elements indexed from A0 to An−1 inclusive. For each Ai, −n ≤ Ai ≤ n.
Create an array C that can be indexed from C−n to C+n, inclusive. Initialize C to all zeros.
Define a pointer D. Initialize D to point to A0.
For 0 ≤ i < n:
If CAi=0, copy Ai to where D points and advance D one element.
Increment CAi.
Set r to the number of elements D has been advanced from A0.
For −n ≤ i ≤ +n:
While 1 < CAi:
Copy i to where D points and advance D one element.
Decrement CAi.
Release C.
Return r. A contains the required values.
A sample implementation is:
#include <stdio.h>
#include <stdlib.h>
#define NumberOf(a) (sizeof (a) / sizeof *(a))
int moveDuplicates(int Array[], int n)
{
int *memory = calloc(2*n+1, sizeof *Array);
if (!memory)
{
fprintf(stderr, "Error, unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
int *count = memory + n;
int *destination = Array;
for (int i = 0; i < n; ++i)
// Count each element. If it is unique, move it to the front.
if (!count[Array[i]]++)
*destination++ = Array[i];
// Record how many unique elements were found.
int result = destination - Array;
// Append duplicates to back.
for (int i = -n; i <= n; ++i)
while (0 < --count[i])
*destination++ = i;
free(memory);
return result;
}
int main(void)
{
int Array[] = { 5, 2, 4, 5, 6, 7, 2 };
printf("There are %d different numbers.\n",
moveDuplicates(Array, NumberOf(Array)));
for (int i = 0; i < NumberOf(Array); ++i)
printf(" %d", Array[i]);
printf("\n");
}
here is the right answer, figured it out by myself.
int moveDup(int* arr, int n)
{
int* seen_before = (int*)calloc(n * 2 + 1, sizeof(int));
assert(seen_before);
int val = 0, count = 0, flag = 1;
int j = 0;
for (int i = 0; i < n; i++)
{
val = arr[i];
if (seen_before[arr[i] + n] == 0)
{
seen_before[arr[i] + n]++;
count++;
continue;
}
else if (flag)
{
j = i + 1;
flag = 0;
}
while (j < n)
{
if (seen_before[arr[j] + n] == 0)
{
count++;
seen_before[arr[j] + n]++;
swap(&arr[i], &arr[j]);
j++;
if (j == n)
{
free(seen_before);
return count;
}
break;
}
/*break;*/
j++;
if (j == n)
{
free(seen_before);
return count;
}
}
}
}
second right answer
int* mem = (int*)calloc(2 * n + 1, sizeof * arr);
assert(mem);
int* count = mem + n;
int* dest = arr;
for (i = 0; i < n; ++i)
{
if (count[arr[i]]++ == 0)
{
*dest = arr[i];
*dest++;
}
}
res = dest - arr;
for (i = -n; i <= n; ++i)
{
while (0 < --count[i])
{
*dest++ = i;
}
}
free(mem);
return res;

how to print a matrix with a negated row more efficiently

I wrote the following function:
void negate_row(const int n, const int r, int *a)
{
if (r == 0)
{
printf("Matrix with negated row: ");
printf("\n");
for (int y = 0; y < 3; y++)
{
*(a + 3 * r + y) = *(a + 3 * r + y) *(-1);
printf("%d ", *(a + 3 * r + y));
}
printf("\n");
for (int y = 0; y < 3; y++)
{
*(a + 3 * r + y) = *(a + 3 * r + y) *(-1);
printf("%d ", *(a + 3 * (r + 1) + y));
}
printf("\n");
for (int y = 0; y < 3; y++)
{
*(a + 3 * r + y) = *(a + 3 * r + y) *(-1);
printf("%d ", *(a + 3 * (r + 2) + y));
}
printf("\n");
}
So basically what happens here is my function takes in a n X 3 matrix and negates a specific row using pointer arithmetic. I have been able to achieve that, I've also been able to figure out how to print that same matrix with the negated row. It's just the way I'm doing it is not efficient at all. I'd have to write an if statement for each row, ex if r == 0,1,2,3,4 etc... is there any way I can do this more efficiently?
Some clarifications: const int n decides the size of the matrix (n x 3), const int r decides what row is negated (0 <= r < n).
A second loop will help. I generally find pointer code a bit harder to read. Particularly with Matrix manipulation you might be better off using array syntax instead of pointer syntax.
for (int y = 0; y < 3; y++)
{
for (int x = 0; x < 3; x++)
{
printf("%d ", *(a + 3 * (r + x) + y));
}
printf("\n");
}
Particular case (3 rows):
int mul = 1, y = 0;
for (int x = 0; x < n; x++) {
mul = x == r ? -1 : 1;
y = (a + 3 * x);
printf("%d ", (*y) * mul);
printf("%d ", (*y + 1) * mul);
printf("%d ", (*y + 2) * mul);
printf("\n");
}
More generic (m rows):
int mul = 1;
for (int x = 0; x < n; x++) {
mul = x == r ? -1 : 1;
for (int y = 0; y < m; y++) {
printf("%d ", ((*(a + m * x + y)) * mul);
}
printf("\n");
}
Note: In new compilers there is also no difference in speed between array or pointer syntax.
You could write a function that accepts a one-dimensional array (a row of your matrix) and then using this function you could in a loop output its all rows or output a selected row.
Here is a demonstrative program.
#include <stdio.h>
void negate_row( const int *a, size_t n, int width )
{
if ( width < 1 ) width = 1;
for ( const int *p = a; p != a + n; ++p )
{
printf( "%*d ", width, -*p );
}
putchar( '\n' );
}
int main(void)
{
enum { M = 3, N = 4 };
int matrix[M][N] =
{
{ 0, 1, 2, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
for ( int ( *p )[N] = matrix; p != matrix + M; ++p )
{
negate_row( *p, N, 3 );
}
return 0;
}
The program output is
0 -1 -2 -4
-5 -6 -7 -8
-9 -10 -11 -12
As you showed a code where you are using pointers tp output elements of an array then in this demonstrative program I am also using pointers everywhere to access elements of an array.
The third parameter of the function specifies the width of the field for an outputted value.
To output the matrix in the reversed order of rows you can use the loop shown in the program blow.
#include <stdio.h>
void negate_row( const int *a, size_t n, int width )
{
if ( width < 1 ) width = 1;
for ( const int *p = a; p != a + n; ++p )
{
printf( "%*d ", width, -*p );
}
putchar( '\n' );
}
int main(void)
{
enum { M = 3, N = 4 };
int matrix[M][N] =
{
{ 0, 1, 2, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
for ( int ( *p )[N] = matrix + M; p != matrix; )
{
negate_row( *--p, N, 3 );
}
return 0;
}
The program output is
-9 -10 -11 -12
-5 -6 -7 -8
0 -1 -2 -4
You can generalize the function easily: as long as the row is within the matrix, your code works for any row. Also note that it is better to use a separate function to print the matrix.
#include <stdio.h>
void negate_row(const int n, const int r, int *a) {
if (r >= 0 && r < n) {
// negate row r
for (int col = 0; col < 3; col++) {
*(a + 3 * r + col) *= -1;
}
}
}
void print_matrix(const int n, int *a, const char *title) {
if (title) {
printf("%s:\n", title);
}
for (int row = 0; row < n; row++) {
for (int col = 0; col < 3; col++) {
printf("%d ", *(a + 3 * row + col));
}
printf("\n");
}
printf("\n");
}
int main() {
int matrix[5 * 3] = {
0, 1, 2,
3, 4, 5,
6, 7, 8,
9, 10, 11,
12, 13, 14,
};
print_matrix(5, matrix, "Matrix");
negate_row(5, 0, matrix);
print_matrix(5, matrix, "Matrix with negated row");
negate_row(5, 3, matrix);
print_matrix(5, matrix, "Matrix with two negated rows");
negate_row(5, 0, matrix);
negate_row(5, 3, matrix);
print_matrix(5, matrix, "Matrix back to origin");
return 0;
}
Output:
Matrix:
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14
Matrix with negated row:
0 -1 -2
3 4 5
6 7 8
9 10 11
12 13 14
Matrix with two negated rows:
0 -1 -2
3 4 5
6 7 8
-9 -10 -11
12 13 14
Matrix back to origin:
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14

Array size changed after sorting

I'm currently working on an assignment which tells me to get the largest count number on a sequence in a array (ex: arr[] = {1,2,3,4,5}, valid sequence is {1,2},{2,3},{5}, or {2,3,4,5}. I've used an algorithm that finds the largest value of an array without sorting it, but, the online judge considers it wrong because it ran for too long (Time Limit Error). So I've changed my code to use a sorting algorithm.
I'm trying to find the largest value in an array by sorting it first, then printing the last value (biggest) of the array, which worked if I input this:
Input:
1 // cases
3 2
2 2 2
Output:
SIZE of Array is: 3
UNSORTED countArr:
0. 1
1. 1
2. 1
(after sorting) SORTED countArr:
0. 1
1. 1
2. 1
However, if I try to have to input multiple "cases" I would get:
Input:
2 // cases
4 11
2 9 1 1
3 2
2 2 2
Output:
SIZE of Array is: 4
UNSORTED countArr:
0. 2
1. 3
2. 2
3. 1
(after sorting) SORTED countArr:
0. 1
1. 2
2. 2
3. 3
SIZE of Array is: 4 //why did the array size become 4, instead of 3
UNSORTED countArr:
0. 1
1. 1
2. 1
3. 3 // and what is this 3 doing here? it should have ended at number 2.
(after sorting) SORTED countArr:
0. 1
1. 1
2. 1
3. 3 // same as above
If anyone could help, could you tell me where I'm wrong?
Source code:
#include <stdio.h>
// all function is for quicksort
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int partition (int arr [], int low, int high) {
int pivot = arr [high];
int i = (low - 1);
for (int j = low; j <= high- 1; j++) {
if (arr [j] < pivot) {
i++;
swap (&arr [i], &arr [j]);
}
}
swap (&arr [i + 1], &arr [high]);
return (i + 1);
}
void quickSort (int arr[], int low, int high) {
if (low < high) {
int pi = partition (arr, low, high);
quickSort (arr, low, pi - 1);
quickSort (arr, pi + 1, high);
}
}
int main () {
int cases, numofElement;
int limit, set [5001], sum = 0, count = 0, countArr [100001], size = 0, largest;
int i, j, k, l, m;
scanf ("%d", &cases);
for (i = 0; i < cases; i++) {
scanf ("%d %d", &numofElement, &limit);
for (j = 0; j < numofElement; j++) {
scanf ("%d", &set [j]);
}
// so the program knows if the array 'set []' is reaching its last digit
set [numofElement] = -2;
for (k = 0; k < numofElement; k++) {
if (set [k] > limit) {
// to skip over or (if all sequence is invalid) to print "-1"
countArr [k] = -1;
continue;
}
for (l = k; l < numofElement; l++) {
sum += set [l];
count += 1;
if ((sum <= limit) && (sum + set [l + 1] > limit || set [l + 1] == -2)) {
countArr [k] = count;
sum = 0;
count = 0;
break;
}
}
}
// count how many number there are in 'countArr []', so we can find its largest value
size = 0;
l = 0;
while (countArr [l] != 0) {
size += 1;
l++;
}
printf ("SIZE of Array is: %d\n", size);
printf ("UNSORTED countArr:\n");
for (j = 0; j < size; j++) {
printf ("%d. %d\n", j, countArr [j]);
}
// sort the 'temp []' array, and output its largest value
quickSort (countArr, 0, size - 1);
printf ("(after sorting) SORTED countArr:\n");
for (j = 0; j < size; j++) {
printf ("%d. %d\n", j, countArr [j]);
}
}
return 0;
}
Is a simple error, you don't reset the element of countArr array to 0 at the beginning of the first for cycle.
If you fix this your program should work.
After this istruction you need to add the reset to zero :
for (i = 0; i < cases; i++){
... reset to zero countArr
... rest of the programm
}

New to GCC - running a array insertion gives me different output locally than on online compiler

I am going through a TuturialsPoint algorithm and trying to run the C code with GCC. Would anyone know why my local output would be different that what is produced by an online C compiler?
#include <stdio.h>
main()
{
int LA[] = {1, 3, 5, 7, 8};
int item = 10, k = 3, n = 5;
int i = 0, j = n;
printf("The original array elements are :\n");
for (i = 0; i < n; i++)
{
printf("LA[%d] = %d \n", i, LA[i]);
}
n = n + 1;
while (j >= k)
{
LA[j + 1] = LA[j];
j = j - 1;
}
LA[k] = item;
printf("The array elements after insertion :\n");
for (i = 0; i < n; i++)
{
printf("LA[%d] = %d \n", i, LA[i]);
}
}
Expected output (from online gcc compiler)
The original array elements are :
LA[0] = 1
LA[1] = 3
LA[2] = 5
LA[3] = 7
LA[4] = 8
The array elements after insertion :
LA[0] = 1
LA[1] = 3
LA[2] = 5
LA[3] = 10
LA[4] = 7
LA[5] = 8
My local output:
The original array elements are :
LA[0] = 1
LA[1] = 3
LA[2] = 5
LA[3] = 7
LA[4] = 8
The array elements after insertion :
LA[0] = 1
LA[1] = 3
LA[2] = 5
LA[3] = 7
LA[4] = 8
LA[5] = 6
I am using gcc version 8.2.0 (MinGW.org GCC-8.2.0-5)
You defined an array of exactly 5 elements.
int LA[] = {1, 3, 5, 7, 8};
So the valid range of indices to access elements of the array is [0, 5).
This array may not be enlarged. So using an index equal to or greater than 5 results in access and overwriting the memory beyond the array.
You need initially to define the array with the number of elements that allows to insert new elements apart from the 5 explicitly initialized elements.
What you mean is something like the following
#include <stdio.h>
int main(void)
{
enum { N = 10 };
int a[N] = { 1, 3, 5, 7, 8 };
size_t n = 0;
while ( a[n] != 0 ) ++n;
printf( "The original array elements are :" );
for ( size_t i = 0; i < n; i++ ) printf( "%d ", a[i] );
putchar( '\n' );
int item = 10;
size_t pos = 3;
size_t j = n;
if ( pos < j )
{
for ( ; j != pos; j-- )
{
a[j] = a[j-1];
}
}
a[j] = item;
++n;
printf( "The array elements after insertion : " );
for ( size_t i = 0; i < n; i++ ) printf( "%d ", a[i] );
putchar( '\n' );
return 0;
}
The program output is
The original array elements are :1 3 5 7 8
The array elements after insertion : 1 3 5 10 7 8
Note: This code snippet
if ( pos < j )
{
for ( ; j != pos; j-- )
{
a[j] = a[j-1];
}
}
can be substituted for this loop
for ( ; pos < j; j-- )
{
a[j] = a[j-1];
}

To sort an array in required manner

I need to sort the elements in the odd positions in the descending order and elements in the even position in ascending order. Here is my code, I'm unable to break the first loop.
#include<stdio.h>
int main()
{
int n, t;
printf("Enter the size of the array\n");
scanf("%d", &n);
int i, a[n];
if ((n > 20) || (n <= 0))
printf("Invalid Size");
else
{
printf("Enter the values\n");
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
for (i = 0; i < n; i + 2)
{
if (a[i] > a[i + 2])
{
t = a[i];
a[i] = a[i + 2];
a[i + 2] = t;
}
}
for (i = 1; i < n; i + 2)
{
if (a[i] < a[i + 2])
{
t = a[i];
a[i] = a[i + 2];
a[i + 2] = t;
}
}
for (i = 0; i < n; i++)
{
printf("%d\n", a[i]);
}
}
}
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
There is no great sense to declare the variable n as having the type int that after that to check whether its value is less than zero. It is much better to declare it as having the type size_t.
And the array should be declared after the check
if ((n > 20) || (n <= 0))
printf("Invalid Size");
else
{
int a[n];
//...
In loops like this
for (i = 0; i < n; i + 2)
the variable i is not increased. It is obvious that you mean i += 2.
And the loops only moves the first minimum even and the first maximum odd elements to the end of the array. You need additional loops that will do the same operation for other elements of the array. That is the implementation of the bubble sort algorithm is incorrect.
Here is a demonstrative program that shows how the array can be sorted according to the requirements for even and odd elements of the array.
#include <stdio.h>
#define N 20
int main(void)
{
int a[N] = { 18, 1, 16, 3, 14, 5, 12, 7, 10, 9, 8, 11, 6, 13, 4, 15, 2, 17, 0, 19 };
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
for ( size_t n = N, last; !( n < 3 ); n = last )
{
for ( size_t i = last = 2; i < n; i++ )
{
if ( ( i % 2 == 0 && a[i] < a[i - 2] ) ||
( i % 2 == 1 && a[i - 2] < a[i] ) )
{
int tmp = a[i];
a[i] = a[i - 2];
a[i - 2] = tmp;
last = i;
}
}
}
for ( size_t i = 0; i < N; i++ )
{
printf( "%d ", a[i] );
}
putchar( '\n' );
return 0;
}
The program output is
18 1 16 3 14 5 12 7 10 9 8 11 6 13 4 15 2 17 0 19
0 19 2 17 4 15 6 13 8 11 10 9 12 7 14 5 16 3 18 1
The most obvious problem is that your for never ends because i is never actually updated. The i+2 in for (i = 0; i < n; i + 2) does not update i which keeps its initia value forever.
Try something like for (i = 0; i < n; i=i+2) instead.
A second problem is that you are not really performing a sorting.
I guess that you are trying to implement some sort of bubble sort.
It sorts using comparison. It is impossible to sort an array using less than n logn operation (when sorting using comparison). You are sorting the array in linear time and this should look as a red flag to you.
Try adding another for as follows:
for (i = 0; i < n; i+= 2)
for (j = i+2; j < n; j+= 2)
if (a[i] > a[j])
{
t = a[i];
a[i] = a[j];
a[j] = t;
}
and most importantly then read about why you need it.
And if you feel brave you can swap the intgers without using an intermediate variable t as follows (read more on the topic here: XOR swap):
if (a[i] > a[j])
{
a[i] = a[i]^a[j];
a[j] = a[j]^a[i];
a[i] = a[i]^a[j];
}
Hope it helps.

Resources