C pointer argument assigned to a parameter with a different value - arrays

I was trying to write a seemingly trivial function in C to get the maximum value in an array of integers. I'm trying to do so using pointers to get a better understanding. (I know how to do this passing the size of the array, the question is not how to do this another way)
#include <stdio.h>
int gimme_largest(int *, int *);
int main(void)
{
int arr[] = {1, 22, 3, 44, 5};
int largest;
printf("In main, arr:\t\t\t %p \n", arr);
printf("In main, arr + sizeof(arr):\t %p\n", arr + 5);
putchar('\n');
largest = gimme_largest(arr, arr + sizeof(arr));
// printf("\n\nThe largest is %d", largest);
return 0;
}
int gimme_largest(int *a, int *lastPlusOne)
{
int largest = *a; // let's assume the first element is the largest one
printf("In gimme_largest, a:\t\t %p\n", a);
printf("In gimme_largest, a + 5:\t %p\n", a + 5);
printf("In gimme_largest, lastPlusOne:\t %p\n", lastPlusOne);
while (a < lastPlusOne) {
if (*a > largest)
largest = *a;
a++;
}
return largest;
}
The problem is that lastPlusOne does not equal a + 5 in the invoked function, but a higher address; can't see why that's happening.

This call
largest = gimme_largest(arr, arr + sizeof(arr));
is invalid. sizeof( arr ) in the case of your program is equal to 5 * sizeof( int ) while for the correct pointer arithmetic you need to use only the number of elements in the array.
That is there shall be
largest = gimme_largest(arr, arr + sizeof(arr) / sizeof( *arr ) );
Thus the expression sizeof(arr) / sizeof( *arr ) is equal to the value 5 that you are using in this call of printf
printf("In main, arr + sizeof(arr):\t %p\n", arr + 5);
Pay attention to that the user can call the function with an empty range when a is equal to lastPlusOne. In this case the function will have undefined behavior because for an empty range there is no largest elemenet.
The function should return a pointer to the largest element.
Also as in C there is no function overloading then the function should be called for constant and non-constant arrays.
Here is a demonstrative program that shows how the functipon can be defined.
#include <stdio.h>
int * gimme_largest( const int *first, const int *last )
{
const int *largest = first;
if ( first != last )
{
while ( ++first != last )
{
if ( *largest < *first ) largest = first;
}
}
return ( int * )largest;
}
int main(void)
{
int arr[] = {1, 22, 3, 44, 5};
const size_t N = sizeof( arr ) / sizeof( *arr );
int *largest = gimme_largest( arr, arr + N );
printf( "The largest number is %d\n", *largest );
return 0;
}
The program output is
The largest number is 44

To get the end address of the array, you can do this by arr + sizeof(arr) / sizeof(arr[0]):
#include <stdio.h>
int gimme_largest(int *, int *);
int main(void)
{
int arr[] = {1, 22, 3, 44, 5};
int largest;
printf("In main, arr:\t\t\t %p \n", arr);
printf("In main, arr + sizeof(arr):\t %p\n", arr + 5);
putchar('\n');
largest = gimme_largest(arr, arr + sizeof(arr) / sizeof(arr[0]));
printf("\n\nThe largest is %d", largest);
return 0;
}
int gimme_largest(int *a, int *lastPlusOne)
{
int largest = *a; // let's assume the first element is the largest one
printf("In gimme_largest, a:\t\t %p\n", a);
printf("In gimme_largest, a + 5:\t %p\n", a + 5);
printf("In gimme_largest, lastPlusOne:\t %p\n", lastPlusOne);
while (a < lastPlusOne) {
if (*a > largest)
largest = *a;
a++;
}
return largest;
}
output:
In main, arr: 000000000062FE00
In main, arr + sizeof(arr): 000000000062FE14
In gimme_largest, a: 000000000062FE00
In gimme_largest, a + 5: 000000000062FE14
In gimme_largest, lastPlusOne: 000000000062FE14
The largest is 44

Related

The sum of array elements using pointer in C

#include <stdio.h>
int main() {
int a[] = { 5, 5, 8, 34, 12, 2 };
int *p;
int i = 0, c = 0;
int sum = 0;
for(p = &a[i]; i < sizeof(a) / sizeof(a[0]); i++) {
sum += *p;
}
printf("the sum is %d\n", sum);
}
I tried to find the sum of array elements using pointer, but the result is not correct. The value of i does seem to increment, but it is not observed in the expression a[i]. I want to know why incrementing i is not having an effect on indexing the array a.
In this for loop
for(p=&a[i];i<sizeof(a)/sizeof(a[0]);i++){
sum+= *p;
}
the pointer p always points to the first element of the array because the pointer is initialized only once p=&a[i] when i is equal to 0 and is not being changed within the for loop.
If you want to use a pointer to access elements of the array in the for loop then the variable i is redundant. Instead write
int a[] = { 5, 5, 8, 34, 12, 2 };
const size_t N = sizeof( a ) / sizeof( *a );
int sum = 0;
for ( const int *p = a; p != a + N; ++p ){
sum += *p;
}
printf( "the sum is %d\n",sum );
Pay attention to that in this declaration within the for statement
const int *p = a;
the array designator a is implicitly converted to pointer to its first element. So it is enough to write as shown above instead of
const int *p = &a[0];
If you want to use pointers, then you need to get rid of the residue from your earlier code which used the subscript operator.
Here p points at &a[0] (a alone decays into an int* here so no need to write out &a[0]) and end points at one element beyond the last element. The iteration should therefore stop when p == end.
#include <stdio.h>
int main(void) {
int a[] = {5, 5, 8, 34, 12, 2};
int sum = 0;
for (int *p = a, *end = a + sizeof a / sizeof *a; p != end; ++p) {
sum += *p;
}
printf("the sum is %d\n", sum);
}

Print prime numbers using pointer arithmetic

My function writePrime has to write all prime numbers from array using pointer arithmetic. I cannot use any other function except main and writePrime.
#include <stdio.h>
void writePrime(int arr[], int n) {
int *q = arr, *qq = arr, i, prime;
while (q < arr + n) {
while (qq < arr + n) {
i = 1;
if (*qq % i != 0)
continue;
else
prime = 1;
i++;
qq++;
}
if (prime == 1)
printf("%d ", *q);
q++;
}
}
int main() {
int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 92, 93, 94, 95, 96};
int n = sizeof(arr) / sizeof(*arr);
writePrime(arr, n);
return 0;
}
This code just prints the same unchanged array. How could I modify this to work?
The variable n should be declared as having the type size_t
size_t n = sizeof(arr) / sizeof(*arr);
because it is the type of an expression with the sizeof operator.
So the function should be declared like
void writePrime( const int arr[], size_t n );
Using two loops with two pointers within the function does not make a sense.
Each variable is divisible by 1. So this code snippet
i = 1;
if (*qq % i != 0)
continue;
else
prime = 1;
also does not make any sense.
And you are using initially uninitialized variable prime that must be reset before processing each element of the array.
The function can be defined the following way
void writePrime( const int arr[], size_t n )
{
for ( const int *p = arr; p != arr + n; ++p )
{
int prime = *p % 2 == 0 ? *p == 2 : *p != 1;
for ( int i = 3; prime && i <= *p / i; i += 2 )
{
if ( *p % i == 0 ) prime = 0;
}
if ( prime ) printf( "%d ", *p );
}
putchar( '\n' );
}

Recursive function for sum

I have this recursive function, and I try to pass the result in 's' variable.
However if I use *s=*s+v[i]; the function works.
But if I try to call sum(v,i+2,s+v[i],n); It doesn't work anymore.
Can someone tell me what is wrong?
Here is the code:
void sum(int v[], int i, int *s, int n)
{
if (i < n)
{
if (v[i] < 0)
{
//*s = *s + v[i];
//sum(v, i + 2, s, n);
sum(v, i + 2, s + v[i], n);
}
else
sum(v, i + 2, s, n);
}
}
int main()
{
int n = 7;
int v[] = { -5,-8,4,4,3,9,-5 };
int i = 0;
int s = 0;
sum(v, i, &s, n);
printf("SUM IS: %d", s);
return 0;
}
There is a major difference between to 2 ways.
The correct one:
*s = *s +v[i]; // increases the int object pointed to by s
sum(v, i + 2, s, n); // still pass the same pointer to sum
The wrong one:
sum(v, i+2, s+v[i], n);
Here, the pointer is increased instead of the pointed object. It is equivalent to:
s = s +v[i]; // s is not dereferenced here!
sum(v, i + 2, s, n); // pass an incorrect pointer to sum
Looks like you have multiple problems that need correction.
First of all, the inner if is not needed. It is unclear what you wanted to do with this. Handling negative numbers separately? If so, it is not needed since the + operator can also handle addition of negative numbers.
Secondly, the s + v[i] adds the value in your array to the pointer to sum, which is not what you want. You need to use the * operator to dereference s here so that the number is added to the sum that the pointer points to. Your own commented-out code does this correctly.
Thirdly, using sum(v, i + 2, s, n); skips alternate elements so to sum the whole array properly, you need to use i + 1 instead of i + 2.
The following code fixes these issues.
void sum(int v[], int i, int *s, int n)
{
if (i < n)
{
*s += v[i];
sum(v, i + 1, s, n);
}
}
int main()
{
int n = 7;
int v[] = { -5,-8,4,4,3,9,-5 };
int i = 0;
int s = 0;
sum(v, i, &s, n);
printf("SUM IS: %d", s);
return 0;
}

Concatenating two integer arrays in C

I am trying to concatenate two integer arrays. This method works well for strings (char*), but for integer arrays the content of the second array is changed.
int main() {
int* a = malloc(8); // 2 integers
int* b = malloc(12); // 3 integers
a[0] = 1;
a[1] = 2;
b[0] = 3;
b[1] = 4;
b[2] = 5;
int* c = malloc(20); // 5 integers
memcpy(c, a, 8);
memcpy(c+8, b, 12);
printf("%d\n", c[0]); // Excpected 1. Prints 1.
printf("%d\n", c[1]); // Excpected 2. Prints 2.
printf("%d\n", c[2]); // Excpected 3. Prints something random.
printf("%d\n", c[3]); // Excpected 4. Prints something random.
printf("%d\n", c[4]); // Excpected 5. Prints something random.
return 0;
}
Forget all about hard-coding variable sizes. That's the root of your problems and makes the code brittle.
The specific problem here though, is that c+8 does pointer arithmetic on an int*. So it means "go 8 int forward from c". Not 8 bytes - it is equivalent to &c[8], which is obviously wrong.
You should rewrite your code according to this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
int* a = malloc(2*sizeof(int));
int* b = malloc(3*sizeof(int));
a[0] = 1;
a[1] = 2;
b[0] = 3;
b[1] = 4;
b[2] = 5;
int* c = malloc(5*sizeof(int));
memcpy(c, a, 2*sizeof(int));
memcpy(c+2, b, 3*sizeof(int));
printf("%d\n", c[0]);
printf("%d\n", c[1]);
printf("%d\n", c[2]);
printf("%d\n", c[3]);
printf("%d\n", c[4]);
return 0;
}
An optional syntax for malloc is to do int* a = malloc(2 * sizeof(*a)), which is fine too, it's a matter of coding style preference.
Due to the pointer arithmetic in this call of memcpy
memcpy(c+8, b, 12);
there is specified an incorrect destination address.
You allocated an array for 5 elements (provided that sizeof( int ) is equal to 4)
int* c = malloc(20)
So due to the pointer arithmetic c + 0 is the address of the first element, c + 1 is the address of the second element, c + 2 is the address of the third element and so on.
As you are trying to fill the array starting from its third element then you have to write
memcpy(c+2, b, 12);
^^^^
It is the same as if to write
memcpy( &c[2], b, 12);
Also do not use magic numbers like 12 or 20. Take into account that sizeof( int ) is implementation defined. So it would be much better to write for example
int* c = malloc( 5 * sizeof( int ) );
or
memcpy( c + 2, b, 3 * sizeof( int ) ;
Your program could look the following way.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( void )
{
size_t n1 = 2;
size_t n2 = 3;
int *a = malloc( n1 * sizeof( int ) );
int *b = malloc( n2 * sizeof( int ) );
int init_value = 1;
for ( size_t i = 0; i < n1; i++ )
{
a[i] = init_value++;
}
for ( size_t i = 0; i < n2; i++ )
{
b[i] = init_value++;
}
size_t n3 = n1 + n2;
int *c = malloc( n3 * sizeof( int ) );
memcpy( c, a, n1 * sizeof( int ) );
memcpy( c + n1, b, n2 * sizeof( int ) );
for ( size_t i = 0; i < n3; i++ )
{
printf("c[%zu]: %d\n", i, c[i] );
}
putchar( '\n' );
free( c );
free( b );
free( a );
return 0;
}
The program output is
c[0]: 1
c[1]: 2
c[2]: 3
c[3]: 4
c[4]: 5
You have to replace memcpy(c+8, b, 12); to memcpy(c+2, b, 12); because first argument of the memcpy function is mean The pointer to the destination array where the content is to be copied, type-casted to a pointer of type void.*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int* a = malloc(8); // 2 integers
int* b = malloc(12); // 3 integers
a[0] = 1;
a[1] = 2;
b[0] = 3;
b[1] = 4;
b[2] = 5;
int* c = malloc(20); // 5 integers
memcpy(c, a, 8);
memcpy(c+2, b, 12);//
printf("%d\n", c[0]); // Excpected 1. Prints 1.
printf("%d\n", c[1]); // Excpected 2. Prints 2.
printf("%d\n", c[2]); // Excpected 3. Prints something random.
printf("%d\n", c[3]); // Excpected 4. Prints something random.
printf("%d\n", c[4]); // Excpected 5. Prints something random.
return 0;
}

Reverse an integer array of length 2^n recursively and return a new array without modifying the original

I encountered the following question in an interview.
Complete this function to return a reversed array without modifying the function signature or the original array. Note that static data types should not be used here at all.
Assume the arrayLength is a power of 2. i.e 2^n. -> I think this is the trick here.
int* reverse(int *array, int arrayLength){
}
Please help.
Note that I could not really think of a solution to the problem. The interviewer hinted at using 2^n for the puspose, but i could not really think of the solution.
How about this:
int* reverse(int *array, int arrayLength){
if (arrayLength==1) {
int* out=(int*)malloc(sizeof(int));
out[0] = array[0];
return out;
}
int* left = reverse(array+arrayLength/2, arrayLength-arrayLength/2);
int* right = reverse(array,arrayLength/2);
int* out = (int*)realloc(left, sizeof(int)*arrayLength);
memcpy(out+arrayLength/2, right, sizeof(int)*(arrayLength/2));
free(right);
return out;
}
Agree with OP the the hint is "2^n". As with many recursive functions: divide and conquer.
This routine first deals with errant paramters and the simple lengths. Next, divide the length in half and reverse each half. Form the result by concatenating the reversed left and right sub-arrays. First, right, then left.
Usual clean-up follows
#include <string.h>
#include <stdlib.h>
int* reverse(int *array, int arrayLength) {
// Check parameters
if (array == NULL || arrayLength < 0) {
; // TBD HandleBadParameters();
}
// Allocate space for result, not much to do if length <= 1
int *y = malloc(arrayLength * sizeof *y);
if (y == NULL) {
; // TBD HandleOOM();
}
if (arrayLength <= 1) {
memcpy(y, array, arrayLength * sizeof *y);
return y;
}
// Find reverse of the two halves
int halflength = arrayLength / 2;
int *left = reverse(array, halflength);
int *right = reverse(&array[halflength], halflength);
// Append them to the result - in reverse order
memcpy(y, right, halflength * sizeof *y);
memcpy(&y[halflength], left, halflength * sizeof *y);
// Clean-up and return
free(right);
free(left);
return y;
}
int* reverse(int *array, int arrayLength){
if(arrayLength == 0) return array;
int* ret = (int*)malloc(arrayLength*sizeof(int));
for(int i=0;i<arrayLength;i++) ret[i] = array[arrayLength-1-i];
return reverse(ret, 0); // technically recursive
}
Here it is (and works):
int *reverse(int *array, int arrayLength)
{
if (arrayLength > 1) {
int i, n = arrayLength >> 1;
int *m = calloc(n, sizeof(int));
memcpy(m, array, n*sizeof(int));
memcpy(array, array + n, n*sizeof(int));
memcpy(array + n, m, n*sizeof(int));
free(m);
reverse(array, n);
reverse(array+n, n);
} /* for */
return array;
} /* reverse */
it can be done without temporary storage, but you have to iterate a little.
int *reverse(int *a, int al)
{
if (al > 1) {
int i, a1 = al >> 1;
for (i = 0; i < a1; i++) {
int temp = a[i];
a[i] = a[i + a1];
a[i + a1] = temp;
} /* for */
reverse(a, a1);
reverse(a+a1, a1);
} /* for */
return a;
} /* reverse */
but, it would be nicer just to exchange from the boundaries to the middle and do it completely iterative.
int *reverse(int *array, int arrayLength)
{
int a, b;
for (a = 0, b = arrayLength-1; a < b; a++, b--) {
int temp = array[a];
array[a] = array[b];
array[b] = temp;
} /* for */
return array;
} /* reverse */
And just for the ones who asked for a non selfmodifying array, this all-inefficient form:
int *reverse(int *array, int arrayLength)
{
int *a1, *a2;
int *res;
if (arrayLength > 1) {
int l = arrayLength >> 1;
a1 = reverse(array, l);
a2 = reverse(array + l, l);
res = calloc(arrayLength, sizeof(int));
memcpy(res, a2, l*sizeof(int));
memcpy(res+l, a1, l*sizeof(int));
free(a1);
free(a2);
} else {
/* we return always memory alloc'd with malloc() so we have to do this. */
res = malloc(sizeof(int));
*res = array[0];
} /* if */
return res;
} /* reverse */
Well, here's one sneaky way, and it doesn't care what length the array is. Note: I'm assuming you can't introduce a new function, it has to be done all within the existing function
if the length is postive, it allocates memory and makes a copy, then calls reverse again with a negative length and the copy, then if the function is called with a negative length, it reverses the first and last inplace, then recursively calls by moving to the next in the array and shrinks the length till there is nothing left to reverse and then the recursive function unwinds
int* reverse(int *array, int arrayLength){
int* result;
if(arrayLength > 0)
{
result =(int*) malloc((sizeof(int)*arrayLength));
memcpy(result, array, sizeof(int)*arrayLength);
reverse(result, -arrayLength);
return result;
}
else if(arrayLength < -1)
{
int end = (-arrayLength)-1;
int temp = array[end];
array[end] = array[0];
array[0] = temp;
return reverse(array+1, arrayLength+2);
}
return array;
}
Considering that arrayLength is always a power of 2. we will apply the function to the two parts of the array then concat them in the reverse way.
Finaly if the array has only one element, we simply return other array with the same element.
int* reverse(int *array, int arrayLength){
int * newArray = NULL;
if(arrayLength == 1){
newArray = (int *)malloc(sizeof(int));
*newArray = array[0];
} else if(arrayLength == 2){
newArray = (int *)malloc(2 * sizeof(int));
newArray[0] = array[1];
newArray[1] = array[0];
} else {
// apply to first half
int * first = reverse(array, arrayLength / 2);
// apply to second half
int * second = reverse(array + arrayLength / 2, arrayLength / 2);
// allocate space
newArray = (int *) malloc(arrayLength * sizeof(int));
// copy parts in reverse way
memcpy(newArray, second, arrayLength / 2 * sizeof(int));
memcpy(newArray + arrayLength / 2, first, arrayLength / 2 * sizeof(int));
// free allocated space for parts
free(first);
free(second);
}
return newArray;
}
I'll give it a shot.
Knowing that the array is of length 2^n means that it can be safely halved. We call the function recursively on each half until length is 2. At this point we swap the two integers. Think { 2,1,4,3,6,5,8,7 }. When we come back from that, each half is then merged opposite of where it came from ( { 4,3,2,1,8,7,6,5} ). Rinse and repeat.
#include <stdio.h>
#include <stdlib.h>
int * reverse( int* arr, int length )
{
if ( length == 1 )
{
int *result = malloc( sizeof( arr[0] ) );
result[0] = arr[0];
return result;
}
int * result = 0;
if ( length == 2 )
{
result = malloc( sizeof( arr[0] ) * 2 );
result[0] = arr[1];
result[1] = arr[0];
}
else
{
int half_length = length / 2;
// named correctly
int * right = reverse( arr, half_length );
int * left = reverse( arr + half_length, half_length );
result = malloc( sizeof( arr[0] ) * length );
for ( int i = 0; i < half_length; ++i )
{
result[i] = left[i];
result[ i + half_length ] = right[i];
}
free( right );
free( left );
}
return result;
}
int main( void )
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
int length = 8;
int *reversed = reverse( arr, length );
for ( int i = 0; i < length; ++i )
{
printf( "%d %d\n", arr[i], reversed[i] );
}
free( reversed );
return 0;
}
for all integer arrays with more than 2 elements.
The basic idea is to swap elements from both ends untill the number of elements remaining is 1.
int* reverse_array(int* array, int arrayLength)
{
if(arrayLength <2)
{
return NULL;
}
else
{
int *array1 = NULL;
int *array2 = NULL;
array1 = malloc(arrayLength*sizeof(int));
memcpy(array1,array,arrayLength*sizeof(int));
/*swap the start and end*/
swap(array1,(array1+arrayLength-1));
/* swap the next pair */
array2 = reverse_array(array1+1,arrayLength-2);
memcpy(array1+1,array2,(arrayLength-2)*sizeof(int));
if(array2!= NULL)
{
free(array2);
}
return array1;
}
}

Resources