question about two sum leetcode problem: brute force approach in C - arrays

I dont understand some small actions that has taken in this code, for example
i) why do we need to do &rs, why cant we just write
int returnSize;
p = twoSum(a, sizeof(a)/sizeof(a[0]), target, int*returnSize);
if(returnSize == 0)
instead of &rs... what is wrong with doing this?
i ran the code here:
#include <stdio.h>
#include <stdlib.h>
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
int i, j;
int* ret_arr = (int*)malloc(2*sizeof(int));
if(ret_arr == NULL){
// *returnSize = 0;
returnSize = 0;
return NULL;
}
for(i = 0; i< numsSize; i++){
for(j = i+1; j< numsSize; j++){
if(nums[i] + nums[j] == target){
//*returnSize = 2;
returnSize = 2;
ret_arr[0] = I;
ret_arr[1] = j;
return ret_arr;
}
}
}
//*returnSize = 0;
returnSize = 0;
free(ret_arr);
return NULL;
}
int main()
{
int a[] = {2,7,11,15};
int returnSize, target = 18;
int *p = NULL;
p = twoSum(a, sizeof(a)/sizeof(a[0]), target, int*returnSize);
//if(*returnSize == 0){
if(returnSize == 0){
printf("target not found");
}else{
printf("target found at indices %d and %d/n", p[0], p[1]);
free(p);
}
return 0;
}
error result:
main.c: In function ‘twoSum’:
main.c:34:28: warning: assignment to ‘int *’ from ‘int’ makes
pointer from integer without a cast [-Wint-conversion]
34 | returnSize = 2;
| ^
main.c: In function ‘main’:
main.c:57:48: error: expected expression before ‘int’
57 | p = twoSum(a, sizeof(a)/sizeof(a[0]), target,
int*returnSize);
| ^~~
full code: https://onlinegdb.com/7OpTpwxZy3
i dont know how this doesn't make sense to the compiler.
ii) Pointer array conceptual Q
we need to declare pointer p in line 60 because to access returned array elements (of two sum function) and print them (like they are used in line ), on screen from main. QUESTION: WHY DO WE NEED POINTER FOR TWO SUM FUNCTION WHEN WE ALREADY HAVE pointer p DECLARED IN MAIN, ITS LIKE POINTER POINTING TO A POINTER(LIKE int*a, int*p, p = a), why does the code work?
error i get if i remove "int*" in line 4(2nd pic), in front of twosum function.
main.c:28:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
28 | twoSum(int* nums, int numsSize, int target, int* returnSize){
| ^~~~~~
main.c: In function ‘twoSum’:
main.c:34:16: warning: returning ‘void *’ from a function with return type ‘int’ makes integer from pointer without a cast [-Wint-conversion]
34 | return NULL;
| ^~~~
main.c:43:24: warning: returning ‘int *’ from a function with return type ‘int’ makes integer from pointer without a cast [-Wint-conversion]
43 | return ret_arr;
| ^~~~~~~
main.c:49:12: warning: returning ‘void *’ from a function with
return type ‘int’ makes integer from pointer without a cast [-
Wint-conversion]
49 | return NULL;
| ^~~~
main.c: In function ‘main’:
main.c:60:4: warning: assignment to ‘int *’ from ‘int’ makes
pointer from integer without a cast [-Wint-conversion]
60 | p = twoSum(a, sizeof(a)/sizeof(a[0]), target, &rs);
| ^
here is the full code for reference:
#include <stdio.h>
#include <stdlib.h>
twoSum(int* nums, int numsSize, int target, int* returnSize){
int i, j;
int* ret_arr = (int*)malloc(2*sizeof(int));
if(ret_arr == NULL){
*returnSize = 0;
return NULL;
}
for(i = 0; i< numsSize; i++){
for(j = i+1; j< numsSize; j++){
if(nums[i] + nums[j] == target){
*returnSize = 2;
ret_arr[0] = I;
ret_arr[1] = j;
return ret_arr;
}
}
}
*returnSize = 0;
free(ret_arr);
return NULL;
}
int main()
{
int a[] = {2,7,11,15};
int rs, target = 18;
int *p = NULL;
p = twoSum(a, sizeof(a)/sizeof(a[0]), target, &rs);
if(rs == 0){
printf("target not found");
}else{
printf("target found at indices %d and %d/n", p[0], p[1]);
free(p);
}
return 0;
}
i hope i provided enough information to understand the question, Question might be fairly simple for experienced programmers but i am just a beginner. Also please explain in easy simple words if you can thinking you are explaining to a beginner.
writing image as texts: i am not sure what to do because in this case image seems easier that text.
i) i tried changing the code as shown below in main function as well as in twosum function.
int returnSize;
p = twoSum(a, sizeof(a)/sizeof(a[0]), target, int*returnSize);
if(returnSize == 0)
ii) i have tried removing int* in line 4(2nd pic), in front of twosum function but i got an error shown here:

There seems to be a basic misunderstanding of what pointers are, how they works and why are used in the posted program.
The function twoSum is trying to find the two elements in an array whose sum equals a given target. The author of this snippet made the following design choices:
// The function returns a POINTER to some memory, allocated in the free store,
// where the two indeces will be stored, or NULL if no elements satisfy the constraint.
int*
twoSum( int* nums, int numsSize // The array is passed as pointer to its first
// element and size (number of elements)
, int target
, int* returnSize ) // This POINTER is used to "return" the size
// of the memory allocated in this function
// to the caller. This may be referred to as
// an "out parameter", it allows the function
// to change the value of a variable stored elsewhere.
{
int i, j;
int* ret_arr = (int*)malloc(2*sizeof(int));
if(ret_arr == NULL){
*returnSize = 0;
// ^ The pointer must be DEREFERENCED to access the value of the pointee.
return NULL;
}
/* [...] */
}
int main()
{
int a[] = {2,7,11,15};
int returnSize, target = 18;
//^^^^^^^^^^^^ This variable is declared as an int.
int *p = NULL;
p = twoSum(a, sizeof(a)/sizeof(a[0]), target, &returnSize);
// We need to pass its ADDRESS here ^^^^^^^^^^^
// because this function is expecting a POINTER to int.
if( returnSize == 0){
// ^^^^^^^^^^ Beeing an int, it must be used as an int value.
printf("target not found");
} else {
printf("target found at indices %d and %d/n", p[0], p[1]);
free(p); // <- Correct. The caller has this responsability.
}
return 0;
}
To answer the first point, it needs the & because it needs to take the address of the variable returnSize declared in main as an int. That address is passed to the function where it is used to initialize the local variable returnSize, which is declared in the signature of the function as a parameter of type int *, a pointer. Please note that those are two different objects, in different scopes, with different lifetimes and different type.
The call can't be written as
p = twoSum(a, sizeof(a)/sizeof(a[0]), target, int*returnSize);
// ^^^^ Syntax error, this isn't a declaration
why do we need pointer for twoSum function when we already have poiner p declared in main?
I'm not sure what the OP's doubts are here. The variable declared in main needs to be assigned a meaningful value, so it uses the value returned by the function. Inside twoSum, a variable of type pointer is needed to allocate the required memory and that is returned to main.
This isn't the only way to accoplish this task, in fact we might prefer to not allocate any memeory inside the function and pass an address instead:
#include <stdio.h>
#include <stdlib.h>
// If there exist two elements whose sum equals the 'target', the function returns 1
// and the indices of these elements are stored in the array 'indices'.
// Otherwise, the function returns 0 and doesn't modify 'indices'.
int
find_indices_of_sum( size_t n, int const* arr
, int target
, int *indices )
{
for(size_t i = 0; i < n; ++i)
{
for(size_t j = i + 1; j < n; ++j)
{
if( arr[i] + arr[j] == target )
{
indices[0] = i;
indices[1] = j;
return 1;
}
}
}
return 0;
}
int main(void)
{
int a[] = {2, 7, 11, 15};
size_t a_size = sizeof a / sizeof *a;
int target = 18;
// Declares the array in main.
int indices[2];
if ( find_indices_of_sum(a_size, a, target, indices) )
{ // Pass the address of its first element ^^^^^^^, the size is known (2).
printf("Target found at indices %d and %d\n", indices[0], indices[1]);
// ^^
// No need to free anything. 'indices' has automatic storage duration.
}
else
{
puts("Target not found");
}
return 0;
}
We can also directly return a struct with all the needed informations from the function, without using any "out parameter".
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct idx_pair
{
size_t first, second;
};
static inline bool is_valid(struct idx_pair p)
{
return p.first != p.second;
}
// The function returns both the indices wrapped in a single struct.
struct idx_pair
find_inidces_of_sum( size_t n, int const *arr
, int target )
{
for(size_t i = 0; i < n; ++i)
{
for( size_t j = i + 1; j < n; ++j)
{
if( arr[i] + arr[j] == target )
{
return (struct idx_pair){ .first = i, .second = j };
// ^^^^^^^^^^^^^^^^^ This is not a cast, it's a
// compound literal with designated initializers.
}
}
}
return (struct idx_pair){ .first = 0, .second = 0 };
}
int main(void)
{
int a[] = {2, 7, 11, 15};
size_t a_size = sizeof a / sizeof *a;
int target = 18;
struct idx_pair solution = find_indices_of_sum(a_size, a, target);
if ( is_valid(solution) )
{
printf("Target found at indices %d and %d\n", solution.first, solution.second);
}
else
{
puts("Target not found");
}
return 0;
}
Note though, that your compiler might not be able to optimize out all the copies and, even if the involved structure isn't that big, the generated assembly might be not optimal on some hardware.

Related

In C - Can I initialize an array (and set the size) from within a function?

I am trying to pass a pointer to a funcion, and in that function create an array, and set the passed pointer to that array.
What I'm trying to do is create an array inside the function and then use that array outside the funcion.
void createArray(int *myPointer)
{
int intArray[20];
*myPointer = &intArray[0]; // This line gets error:
// assignment makes integer from pointer without a cast [-Wint-conversion]
for (int i = 0; i < 20; i++)
{
intArray[i] = i + 10;
}
}
int main(void)
{
int *intPointer;
createArray(&intPointer);
for (int i = 0; i < 20; i++)
{
printf("%d : %d \n", i, intPointer[i]);
}
return 0;
}
You meant to use
void createArray(int **myPointer)
That will resolve the two type errors.
But that will make main's pointer point to a variable that no longer exists after createArray returns. That's bad. And that's why you have to use malloc instead of automatic storage.
void createArray( int **myPointer ) {
int *intArray = malloc( 20 * sizeof(int) );
*myPointer = intArray; // Same as `&intArray[0]`
if ( !intArray )
return;
for ( int i = 0; i < 20; i++ )
intArray[i] = i + 10;
}
int main(void) {
int *intPointer;
createArray(&intPointer);
if ( intPointer ) {
perror( NULL );
exit( 1 );
}
for (int i = 0; i < 20; i++)
printf( "%d: %d\n", i, intPointer[i] );
return 0;
}
The reason for the compiler error is the *myPointer dereferencing, which gives you the content of type int that the pointer points at. The compiler is saying that you can't assign the pointer &intArray[0] to a plain int.
Besides being invalid C, it wouldn't change where the pointer points. To do that, you would have to do myPointer = &intArray[0];. However, in this case you can't do that either because the myPointer is just a local pointer variable inside the function - a local copy of the pointer you passed. You need a way to update the pointer in main().
Furthermore, we can never return a pointer to local data (data with "automatic storage duration") because that data ceases to be valid as soon as we leave the function.
The normal solution is to create dynamically allocated memory instead, since such memory persists throughout the execution of the program (or until you explicitly free it). There are two different ways to write a function for that:
#include <stdlib.h> // for malloc
int* createArray (void)
{
int* result = malloc(20 * sizeof(*result));
if(result == NULL)
return NULL; // some error handling will be required here
for (int i = 0; i < 20; i++)
{
result[i] = i + 10;
}
return result;
}
...
int *intPointer = createArray();
...
free(intPointer);
Alternatively you could pass the pointer itself by value, so that by doing the *myPointer = ...; assignment, you refer to where a int** points at:
#include <stdlib.h> // for malloc
void createArray (int** myPointer)
{
int* result;
result = malloc(20 * sizeof(*result));
if(result == NULL)
{
/* some error handling will be required here */
}
for (int i = 0; i < 20; i++)
{
result[i] = i + 10;
}
*myPointer = result;
}
...
int *intPointer;
createArray(&intPointer);
...
free(intPointer);
Either of these are ok and which one you use is mostly a matter of design. It's easier syntax to have the pointer returned, but then normally the return of functions is reserved for some error code.

how to find out if a serie is sorted using pointers in c

i have the following program in c lanquage:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
bool is_sorted ( int *array , int num , int prev , int *index);
int main ()
{
int N;
int i;
int prev;
int data[100];
bool flag;
printf("Enter length:\n");
scanf("%d",&N);
printf("Enter %d integers:\n" ,N);
for (i =0; i<N; i++)
{
scanf("%d",&data[i]);
}
printf("Enter previous number:\n");
scanf("%d",&prev);
int *index= NULL;
flag = is_sorted(data,N,prev,index);
if ( !flag )
{
printf("%d ", *index);
}
}
bool is_sorted ( int *array , int num , int prev , int *index)
{
if ( prev > array[0] )
{
index=prev;
return false;
}
for ( int i=0; i<num; i++)
{
if ( array[i] > array[i+1] )
{
index = array[i];
return false;
}
}
return true;
}
The function is_sorted takes as input an array of integers and another one random integer and returns true if prev < array[0] < array[1] < ... < array[n].
I am using a pointer in order to find which is the first element to spoil the serie's order but i am a little bit confused with pointer's syntax.
Running it i am getting the following results:
pointers.c:43:14: warning: assignment to ‘int *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
43 | index=prev;
| ^
pointers.c:51:19: warning: assignment to ‘int *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
51 | index = array[i];
index is a pointer to an integer. You need to dereference the pointer to assign to the variable that it points to in the caller.
*index = prev;
...
*index = array[i];

Function to check all elements of an array

I want to make a function to check all elements of an array. But how to pass an array as parameter of a function correctly? I've tried to pass a pointer but it doesn't work, compiler don't even want to compile that code. What am I doing wrong? Please help!
#include <stdio.h>
#define N 10
int iseven(int *A); // prototype
int main(void)
{
int i;
int A[N]; // array to check
for (i = 0; i < N; i++)
scanf("%d", &A[i]);
i = iseven(*A);
if (i == 1)
printf("All numbers are even!\t\n");
else
printf("Not all numbers are even!\t\n");
return 0;
}
int iseven(int *A)
{
int i;
int flag = 1;
for (i = 0; i < N; i++)
if (((A[i] % 2) == 0) && (A[i] >= 2))
continue;
else
{
flag = 0;
break;
}
return flag;
}
gcc array.c -o array.exe
array.c: In function 'main':
array.c:16:14: warning: passing argument 1 of 'iseven' makes pointer from integer without a cast [-Wint-conversion]
i = iseven(*A);
^
array.c:5:5: note: expected 'int *' but argument is of type 'int'
int iseven(int *A); // array to check
^
You need to call the function in the form
i = iseven(A);
Using i = iseven(*A); means that you are dereferencing the value at address A and passing it, which effectively means you are passing the first element of the array to the function.
This is the reason the compiler complains that the function receives an int when it was expecting an int*

How to return an array from a function with pointers

i'm trying to figure out how to return an array from a function in the main().
I'm using C language.
Here is my code.
#include <stdio.h>
int *initArray(int n){
int i;
int *array[n];
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
main(){
int i, n = 5;
int *array[n];
array[n] = initArray(n);
printf("Here is the array: ");
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
printf("\n\n");
}
And this is the errors the console gives me:
2.c: In function ‘initArray’:
2.c:8:13: warning: assignment makes pointer from integer without a cast [enabled by default]
array[i] = i*2;
^
2.c:11:3: warning: return from incompatible pointer type [enabled by default]
return array;
^
2.c:11:3: warning: function returns address of local variable [-Wreturn-local-addr]
2.c: In function ‘main’:
2.c:23:4: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d ", array[i]);
^
It's impossible!
I hate being a noob :(
If you could help, with explanations, I would appreciate! :D
Edit: iharob's answer is better than mine. Check his answer first.
Edit #2: I'm going to try to explain why your code is wrong
Consider the 2nd line of main() in your question:
int *array[n];
Let's try to read it backwards.
[n]
says we have an array that contains n elements. We don't know what type those elements are and what the name of the array is, but we know we have an array of size n.
array[n]
says your array is called array.
* array[n]
says you have a pointer to an array. The array that is being pointed to is called 'array' and has a size of n.
int * array[n];
says you have a pointer to an integer array called 'array' of size n.
At this point, you're 3/4 way to making a 2d array, since 2d arrays consist of a list of pointers to arrays. You don't want that.
Instead, what you need is:
int * array;
At this point, we need to examine your function, initArray:
int *initArray(int n){
int i;
int *array[n];
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
The second line of initArray has the same mistake as the second line of main. Make it
int * array;
Now, here comes the part that's harder to explain.
int * array;
doesn't allocate space for an array. At this point, it's a humble pointer. So, how do we allocate space for an array? We use malloc()
int * array = malloc(sizeof(int));
allocates space for only one integer value. At this point, it's more a variable than an array:
[0]
int * array = malloc(sizeof(int) * n);
allocates space for n integer variables, making it an array:
e.g. n = 5:
[0][0][0][0][0]
Note:The values in the real array are probably garbage values, because malloc doesn't zero out the memory, unlike calloc. The 0s are there for simplicity.
However, malloc doesnt always work, which is why you need to check it's return value:
(malloc will make array = NULL if it isn't successful)
if (array == NULL)
return NULL;
You then need to check the value of initArray.
#include <stdio.h>
#include <stdlib.h>
int *initArray(int n){
int i;
int *array = malloc(sizeof(int) * n);
if (array == NULL)
return NULL;
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
int main(){
int i, n = 5;
int *array = initArray(n);
if (array == NULL)
return 1;
printf("Here is the array: ");
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
free(array);
printf("\n\n");
return 0;
}
You can't just return an array like that. You need to make a dynamically allocated array in order to do that. Also, why did you use a 2d array anyway?
int array[5];
is basically (not completely) the same as:
int * array = malloc(sizeof(int) * 5);
The latter is a bit more flexible in that you can resize the memory that was allocated with malloc and you can return pointers from functions, like what the code I posted does.
Beware, though, because dynamic memory allocation is something you don't wanna get into if you're not ready for tons of pain and debugging :)
Also, free() anything that has been malloc'd after you're done using it and you should always check the return value for malloc() before using a pointer that has been allocated with it.
Thanks to iharob for reminding me to include this in the answer
Do you want to initialize the array? You can try it like this.
#include <stdio.h>
void initArray(int *p,int n)
{
int i;
for(i = 0; i < n; i++)
{
*(p+i) = i*2;
}
}
void main(void)
{
int i, n = 5;
int array[n];
initArray(array,n);
printf("Here is the array: ");
for(i = 0; i < n; i++)
{
printf("%d ", array[i]);
}
printf("\n\n");
}
If you don't want to get in trouble learning malloc and dynamic memory allocation you can try this
#include <stdio.h>
void initArray(int n, int array[n]) {
int i;
for (i = 0 ; i < n ; i++) {
array[i] = i * 2;
}
}
int main() { /* main should return int */
int i, n = 5;
int array[n];
initArray(n, array);
printf("Here is the array: ");
for(i = 0 ; i < n ; i++) {
printf("%d ", array[i]);
}
printf("\n\n");
return 0;
}
as you see, you don't need to return the array, if you declare it in main(), and pass it to the function you can just modify the values directly in the function.
If you want to use pointers, then
#include <stdio.h>
int *initArray(int n) {
int i;
int *array;
array = malloc(n * sizeof(*array));
if (array == NULL) /* you should always check malloc success */
return NULL;
for (i = 0 ; i < n ; i++) {
array[i] = i * 2;
}
return array;
}
int main() { /* main should return int */
int i, n = 5;
int *array;
array = initArray(n);
if (array == NULL) /* if null is returned, you can't dereference the pointer */
return -1;
printf("Here is the array: ");
for(i = 0 ; i < n ; i++) {
printf("%d ", array[i]);
}
free(array); /* you sould free the malloced pointer or you will have a memory leak */
printf("\n\n");
return 0;
}

error: variable-sized array may not be initialized

I keep having these errors with my array. How am I supposed to return a 2d array of unknown size? I'm trying to manipulate a pbm image by converting it into an array and then doing array manipulations. Here is my code
typedef struct
{
unsigned char blackWhite;
} PBMPixel;
typedef struct
{
int x, y;
PBMPixel *data;
} PBMImage;
This is defined in my header file which hasn't given me any issues. Later on, I have this:
char * ArrayCreate(PBMImage *img, int x, int y)
{
char ManipArray[x][y];
int i = 0;
int j= 0;
for( i=0; i < x; i++)
{
for ( j=0; j < y; j++)
{
char ManipArray[i][j] = img->data[(i*(j+1)+j)].blackWhite;
j++;
}
i++;
}
return ManipArray;
}
These are the errors I keep getting back:
P-MFunctionHolder.c: In function 'ArrayCreate':
P-MFunctionHolder.c:171:4: error: variable-sized object may not be initialized
P-MFunctionHolder.c:176:2: warning: return from incompatible pointer type [enabled by default]
P-MFunctionHolder.c:176:2: warning: function returns address of local variable [enabled by default]
I'm using MinGW and Windows 8 if that helps, but I doubt that is the problem. I also didn't post the entire code because that's about 260 lines and gives a bunch of the exact same errors.
How am I supposed to return a 2d array of unknown size?
A typical solution to this problem is to allocate memory on the heap to a pointer, implicitly passing the responsibility for deallocation to the caller.
For example:
char * ArrayCreate(PBMImage *img, int x, int y)
{
char *const ManipArray = malloc(x * y * sizeof(char));
int i = 0;
int j= 0;
for( i=0; i < x; i++)
{
for ( j=0; j < y; j++)
{
ManipArray[i * y + j] = img->data[(i*(j+1)+j)].blackWhite;
j++;
}
i++;
}
return ManipArray;
}

Resources