简体   繁体   中英

C - return pointer to an array

I have to write a function with the signature

 int *greater (int n[], int length, int value) 

that returns a pointer to an array containing the elements in n[] that are greater than a value. The array returned must be exactly the length to hold the values greater than value and have no unused elements.

I have the following code:

#include <stdio.h>

int k=0, v[100];

int * greater(int n[], int length, int value)
{
    for (int i=0; i<length-1; i++)
        if (n[i]>value)
        {
            v[k]=n[i];
            k++;
        }
    int *p=v;
    return p;
}
int main ()
{
    int a[]={1,2,3,4,5};
    int *p=greater (a,5,3);
    int *end; end=v+k;
    while (p<=end)
    {
        printf ("%i ", *p);
        p++;
    }
}

The problem is that p will only hold the value of 4, therefore it will print 4 0, instead of 4 5. Any ideas what I am doing wrong?

To resolve your issue, do not use a global array( v[100]; ). Instead,

  1. define a pointer inside greater()
  2. allocate memory dynamically using malloc() .
  3. resize the memory as per the requirement using realloc()
  4. return the pointer.

In the lights of the comment from Mr. @alk , you can get the number of elements in the array using the global variable k .

Note: once you're done using the memory, don't forget to free() the pointer from main() .

BTW, the recommended signature of main() is int main(void)


EDIT:

Also, for the logical part, as mentioned in the comments by Mr. @BLUEPIXY and @karma_geek , please note

  1. change the looping condition to for (int i=0; i<length; i++)
  2. Change the while loop to while (p<end)

I would suggest 2 changes in addition to the ones already mentioned:

Iterate the for loop till <length , as <legnth-1 would not cover the entire array.

int * greater(int n[], int length, int value)
{
    for (int i=0; i<length; i++)
        if (n[i]>value)
        {
            v[k]=n[i];
            k++;  // increment
        }
    int *p=v;
    return p;
}

Also, change the formula for end. This is because in the function, where the increment occurs, k=0 would change as: k=1 for 4 > 3 , then k=2 for 5 > 3 . Now,

end = v + k ; 

would result in end = v + 2 when instead we wanted 1 lesser value.

int *end; end=v+k-1;  

Code with correct output

As the specs do not require to return the size of the target array, allocating a new array inside the fucntion make the pointer returned quiet useless as the caller does not know which elements (if any) are valid.

So the only sane approach would be to not allocate memory for the target, to not even use a second array. This also is not required by the specs, so you might like to take following approach

  1. Sort the input.
  2. Find the 1st element greater then the give threshold, by simply looping over the result from 1..
  3. Return the pointer to the element found in 2.

Example:

#include <qsort.h>

int cmp(const void * pv1, const void * pv2)
{
  int i1 = *((int *) pv1);
  int i2 = *((int *) pv2);

  return (i1 - i2);
}

int * greater(int n[], int length, int value)
{
  qsort(n, sizeof *n, length, cmp);

  while (0 < length)
  {
    --length;
    if (n[length] > value)
    {      
      break;
    }
  }

  return n + length + 1;
}

The only req/

array returned must be exactly the length to hold the values greater than valu

is met.

Modify your search function to return the number of elements found in a pointer parameter. Allocate the results array within the function, minimize the number of possible allocations in the function, shrink the results array before returning.

For example:

#include <stdio.h>
#include <stdlib.h>

int *
greater(
        const int const n[],
        const size_t n_elem,
        const int threshold,
        size_t *n_greater
        )
{
    size_t i = 0;
    size_t n_found = 0;
    size_t n_allocated = 0;
    int *ret = NULL;

    for (i = 0; i < n_elem; i += 1) {
        if (n[i] > threshold) {
            n_found += 1;
            if (n_found > n_allocated) {
                size_t new_size = (n_allocated < (n_elem / 2))
                                ? 2 * n_found
                                : n_elem
                ;
                int *tmp = realloc(ret, new_size * sizeof(*tmp));
                if (!tmp) {
                    fputs("Failed to allocate memory", stderr);
                    exit(EXIT_FAILURE);
                }
                n_allocated = new_size;
                ret = tmp;
            }
            ret[n_found - 1] = n[i];
        }
    }
    if (n_allocated > n_found) {
        int *tmp = realloc(ret, n_found * sizeof(*tmp));
        if (!tmp) {
            fputs("Failed to shrink result array", stderr);
            exit(EXIT_FAILURE);
        }
        ret = tmp;
    }
    *n_greater = n_found;
    return ret;
}

int main (void)
{
    int a[] = {1,2,3,4,5,1,1,2,3,7,6,5,5,0,-1,7};
    size_t n_greater_than_three = 0;
    size_t i =0;
    int *p = greater(a, sizeof(a)/sizeof(a[0]), 3, &n_greater_than_three);

    for (i = 0; i < n_greater_than_three; i += 1) {
        printf("%d\n", p[i]);
    }

    free(p);

    return EXIT_SUCCESS;
}

Output:

C:\...\Temp> greater.exe
4                                             
5                                             
7                                             
6                                             
5                                             
5                                             
7

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