简体   繁体   中英

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM