0

I had to make a function that would allocate dynamic memory for a new array and then fill that array in with random numbers from [low;high] interval. If the function is successful then return a pointer to the first digit of a new array, in case of failure return NULL. I have my program working perfectly fine, I get the results I need but I get 2 warnings. 1) warning: returning 'void *' from a function with return type 'int' makes integer from... 2) warning: passing argument 1 of 'createArray' from incompatible pointer type. Oh and in this else if(firstDigit == NULL) I get 'warning: comparison between pointer and integer'. I tried changing my function to int* createArray(int *pt, int size) instead of simple int createArray(int *pt, int size) but that did not help.

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

int createArray(int *pt, int size) {
    srand(time(NULL));
    int *x;
    int count = 0;
    int low = 2;
    int high = 5;
    x = (int*) malloc(size * sizeof(int));

    if(x == NULL) {
        printf("Memory cannot be allocated\n");
        exit(0);
    }
    //filling the array with random numbers from [low;high]
    for(int i = 0;i < size; ++i) {
        x[i] = low + rand()%(high-low+1);
        ++count;
    }
    //returning a pointer to the first digit of the new array
    if(count == size) {
        pt = &x[0];
        return *pt;
    }
    else {
        return NULL;
    }
    free(x);
}

int main()
{
    int *pt;
    int size = 5;
    int firstDigit = createArray(&pt, size);
    if(firstDigit > 0){
        printf("First digit is: %d", firstDigit);
    }
    else if(firstDigit == NULL) {
        printf("Something went wrong");
    }
}
Aldomond
  • 171
  • 6
  • 2
    The `free(x)` at the bottom of `createArray()` is unreachable code; both the `if` and `else` clauses before it end with `return`. Your function should be returning an `int *`, not an `int`. You might be getting a warning about the `return NULL:` converting a pointer to an integer (possibly mentioning 'different size'). – Jonathan Leffler Nov 01 '20 at 16:50
  • Consequently, the code in `main()` should probably use `int *firstDigit = createArray(…);`. Then the comparison in `else if (firstDigit == NULL) {` is correct — but the prior `if (firstDigit > 0)` is dubious and you should actually reverse the testing: `if (firstDigit == NULL) { fprintf(stderr, "Something went wrong with memory allocation\n"); exit(1); } else { printf("First digit is: %d\n", firstDigit[0]);` }` — noting that: errors go to `stderr`; messages end with newlines; programs should exit with a non-zero status on failure. – Jonathan Leffler Nov 01 '20 at 16:53
  • 1
    You might want to ask only one question instead of several. Would be easier to answer that way. – anatolyg Nov 01 '20 at 16:54
  • You are trying to assign the pointer to the allocated memory to `pt` in `main()`, but you have a pointer type mismatch in the arguments to ``createArray()``. That isn't helping your cause either. – Jonathan Leffler Nov 01 '20 at 17:04
  • You are mixing up integers, pointers and pointer of pointers. Keep in mind: `int x = 5; int * pt = &x; int ** ptpt = &pt` – moritz Nov 01 '20 at 17:19

3 Answers3

1

You are getting the "incompatible pointer type" error because, in your main function, pt is of type int*. Then, when you call createArray, you are passing &pt, which is of type int**. Pretty much, you are passing a pointer to a pointer to an int versus just a pointer to an int.

The warning regarding returning void* from a function with return type int is referring to returning NULL in the failure case. I think there is a misunderstanding here -- with the way you have declared your function, it is not returning a pointer to an int like you describe in your comment: //returning a pointer to the first digit of the new array. You are only returning an int. NULL is of type void*, so it makes sense that it did not match the return type.

I recommend reviewing pointers in C since there seems to be confusion between normal ints, pointers to ints, and pointers to pointers to ints haha.

Here is something that could work, although it changes what you are trying to do slightly:

int* createArray(int size) {
    srand(time(NULL));
    int *x;
    /* no need to verify loop runs correct # of times
    int count = 0;
    */
    int low = 2;
    int high = 5;
    x = /*do not cast malloc calls */ malloc(size * sizeof(int));

    if(x == NULL) {
        printf("Memory cannot be allocated\n");
        // exit with nonzero value to indicate error
        exit(1);
    }
    //filling the array with random numbers from [low;high]
    for(int i = 0;i < size; ++i) {
        x[i] = low + rand()%(high-low+1);
        ++count;
    }
    //returning a pointer to the first digit of the new array
    /* no need to verify that the loop has run the correct # of times
    if(count == size) { */

    return x;
    
    /* no need for this check
    else {
        return NULL;
    }
    free(x);*/
}

int main()
{
    int *pt;
    int size = 5;
    // adapting to new signature
    pt = createArray(size);
    // check for NULL before trying to use value
    // even though you decide to exit(1) on failure, so pt will never be NULL
    if (pt == NULL) {
        printf("Something went wrong\n");
        return 1;
    }
    // accessing first element
    else if (pt[0] > 0) {
        printf("First digit is %d\n", pt[0]);
    }

    free(pt);
}

I recommend you work through this code and read up some more about pointers, since there were various things that should have been fixed.

Here is a link to why you shouldn't cast malloc.

The other answer has some great tips as well.

deadbird11
  • 147
  • 2
  • 8
1

The warning indicates a type mismatch. createArray returns an int but the type of NULL is void *. createArray expects its first parameter to be of type int * but the type of the expression &pt is int **.

Here is my take on the question:

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

int *createArray(int size) {
    srand(time(NULL));
    int *x;
    int low = 2;
    int high = 5;
    x = malloc(size * sizeof(int));

    if (x != NULL) {
        //filling the array with random numbers from [low;high]
        for(int i = 0;i < size; ++i)
            x[i] = low + rand()%(high-low+1);
    }

    return x;
}

int main()
{
    int size = 5;
    int *pt = createArray(size);
    if (pt == NULL)
        return 1;

    int firstDigit = *pt;
    if(firstDigit > 0){
        printf("First digit is: %d", firstDigit);
    }
    else if(firstDigit == NULL) {
        printf("Something went wrong");
    }

    free(pt);
}
Jim Morrison
  • 401
  • 4
  • 9
0

There are a variety of problems, some serious, some mundane.

The free(x) at the bottom of createArray() is unreachable code; both the if and else clauses before it end with return. You are leaking the memory you allocate in createArray() — you are not successfully returning a pointer to the memory to the main() function (and you aren't attempting to release it there either), and you are not successfully releasing it in the function — which wouldn't be much like a 'create array' function if it also destroyed the array it created.

One interpretation of the requirements (call it "Interpretation A") is that your function should be returning an int *, not an int. You might be getting a warning about the return NULL converting a pointer to an integer (possibly mentioning 'different size').

Under this interpretation, the code in main() should probably use int *firstDigit = createArray(…);. Then the comparison in else if (firstDigit == NULL) { is correct — but the prior if (firstDigit > 0) is dubious and you should actually reverse the testing:

if (firstDigit == NULL)
{
    fprintf(stderr, "Something went wrong with memory allocation\n");
    exit(1);
}
printf("First digit is: %d\n", firstDigit[0]);

Note that:

  • errors go to stderr;
  • messages end with newlines;
  • programs should exit with a non-zero status on failure.

Under this interpretation, you wouldn't pass pt or &pt to the function; you'd simply assign the return value from the function to pt.

However, an alternative interpretation (call it "Interpretation B") is that you are trying to assign the pointer to the allocated memory to pt in main(), but then you have a pointer type mismatch in the arguments to createArray(). That isn't helping your cause either.

Fixed code for Interpretation A:

/* SO 6463-4370 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static int *createArray(int size)
{
    int low = 2;
    int high = 8;   /* Increased from 5 to 8 */
    int *x = (int *) malloc(size * sizeof(int));

    if (x == NULL)
    {
        fprintf(stderr, "Memory cannot be allocated\n");
        exit(1);
    }
    // filling the array with random numbers from [low;high]
    for (int i = 0; i < size; ++i)
    {
        x[i] = low + rand() % (high - low + 1);
    }
    // returning a pointer to the first digit of the new array
    return x;
}

int main(void)
{
    srand(time(NULL));
    int size = 5;
    int *pt = createArray(size);
    if (pt == NULL)
    {
        fprintf(stderr, "Something went wrong\n");
        exit(1);
    }
    printf("First digit is: %d\n", pt[0]);
    for (int i = 0; i < size; i++)
        printf("  [%d] %d\n", i, pt[i]);
    free(pt);
    return 0;
}

Output from Interpretation A:

First digit is: 5
  [0] 5
  [1] 8
  [2] 6
  [3] 6
  [4] 2

Fixed code for Interpretation B:

/* SO 6463-4370 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static int createArray(int **pt, int size)
{
    int *x;
    int count = 0;
    int low = 2;
    int high = 5;
    x = (int *) malloc(size * sizeof(int));

    if (x == NULL)
    {
        fprintf(stderr, "Memory cannot be allocated\n");
        exit(1);
    }
    // filling the array with random numbers from [low;high]
    for (int i = 0; i < size; ++i)
    {
        x[i] = low + rand() % (high - low + 1);
        ++count;
    }
    // Assigning a pointer to the first digit of the new array,
    // and returning the first digit of the array
    *pt = x;
    return x[0];
}

int main(void)
{
    srand(time(NULL));
    int *pt;
    int size = 5;
    int firstDigit = createArray(&pt, size);
    if (firstDigit == 0)
    {
        fprintf(stderr, "Something went wrong\n");
        exit(1);
    }
    printf("First digit is: %d\n", firstDigit);
    for (int i = 0; i < size; i++)
        printf("  [%d] %d\n", i, pt[i]);
    free(pt);
    return 0;
}

Output from Interpretation B:

First digit is: 3
  [0] 3
  [1] 3
  [2] 2
  [3] 4
  [4] 4

I will observe that Interpretation B is less flexible and less like idiomatic C code. It's not wrong, but it isn't the way it is normally done. The first digit is easily obtained when you have the whole array. We can also debate the wisdom of exiting from within the function — it would be better to return the null pointer and have the calling code report the error. This is particularly true for code that will live in a library. This also affects the design of the function.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thank you. I am new to pointers so having more than one example is very useful :) – Aldomond Nov 01 '20 at 17:45
  • YW. See also [`srand()` — why call it only once?](https://stackoverflow.com/questions/7343833/srand-why-call-it-only-once/) for hints about why I moved the call from inside the `createArray()` function to the `main()` function. In this context, where you are only calling `createArray()` once, it was harmless enough, but in bigger programs, calling it multiple times (probably with the same time value, unless you had to wait for user input somewhere along the line), calling `srand()` in the function is counter-productive. – Jonathan Leffler Nov 01 '20 at 17:50