0

I'm new to coding and started learning pointers and i'm stuck at a question.

How do I take the array input and print the same array using pointers?

Also it'll be great if you can guide me how to pass variables from function to main(). thanks

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

int* record_array (int *size_ptr);
int* print_array (int *array_ptr [], int *size_ptr);


int* record_array (int *size_ptr)
{
    int *array_ptr = (int*) malloc(*size_ptr*sizeof(int));
    for (int index = 0;index < *size_ptr;++index)
    {
        printf("Enter element at index %d", index);
        scanf("%d", &array_ptr[index]);

    }
    return array_ptr;

}




int* print_array (int *array_ptr [], int *size_ptr)
{
    for (int index = 0;index < *size_ptr;++index)
    {
        printf("%d ",array_ptr[index]);
    }
    int *pass = array_ptr;
    return pass;
}

int main()
{
    int size = 0;

    printf("How many elements do you want?");
    scanf("%d", &size);
    record_array(&size);
    print_array(&array_ptr,&size);
    free(pass);


    return 0;
}
Gerhard Stein
  • 1,543
  • 13
  • 25
default-303
  • 361
  • 1
  • 4
  • 15
  • First, understand that on-access (subject to 4-exceptions not relevant here) an array is converted to a pointer to the first element [C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)](http://port70.net/~nsz/c/c11/n1570.html#6.3.2.1p3) In your case the parameter `int *array_ptr []` ask for an *array-of-pointers* to `int`, you simply need `int *array_ptr`... In C, there is no need to cast the return of `malloc`, it is unnecessary. See: [Do I cast the result of malloc?](http://stackoverflow.com/q/605845/995714) – David C. Rankin May 31 '20 at 08:06

1 Answers1

1

You are close, but you have used int *array_ptr [] in int* print_array (int *array_ptr [], int *size_ptr) incorrectly. You further have no pointer in main() to hold the address returned by int *record_array (int *size_ptr) to use in main() and free when it is no longer needed. print_array simply prints the array and returns nothing (it shouldn't return anything) so it should just be type void, e.g. void print_array (int *array_ptr, int *size_ptr)

On access, (subject to 4-exceptions not relevant here), an array is converted to a pointer to the first element C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3). When you want to pass an array, you simply pass the array as a parameter and it is converted to a pointer automatically.

Also note, there is NO array in the entirety of your code. You declare a pointer and then allocate a block of memory to hold your integer values and you assign the starting address for that block to your pointer. (e.g. the pointer holds the starting address for the allocated block as its value, it "points" to that block of memory)

For starters, in main(), you need a pointer to hold the address returned by record_array, e.g.

    int size = 0;
    int *array = NULL;  /* you need a pointer to hold the address of your array */

In record_array (and for every allocation), you must check the return of malloc() to validate whether it succeeded or failed, e.g.

int *record_array (int *size_ptr)
{
    int *array_ptr = malloc (*size_ptr * sizeof *array_ptr);

    if (!array_ptr) {   /* validate EVERY allocation */
        perror ("malloc-array_ptr");
        return NULL;
    }
    ...        

(note: the use of the dereferenced pointer to set the type-size for the allocation. Using the dereference pointer -- you will never get it wrong. In C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?)

With input, you must validate every input, e.g. in record_array() that would be:

    for (int index = 0; index < *size_ptr; index++)
    {
        printf ("Enter element at index %d: ", index);
        if (scanf ("%d", &array_ptr[index]) != 1) {
            fputs ("error: invalid integer input.\n", stderr);
            return NULL;
        }

    }

Expanding a bit on the validations, every time you do something in your code that can fail (like take user input or allocation memory), it is imperative that you validate the return before using the results in your code. Above, if you simply do scanf ("%d", &array_ptr[index]) a simply slip and tapping 'r' instead of '5' would go unnoticed but lead to invalid results in your code (and perhaps Undefined Behavior if it occurred on the first character)

So to prevent using invalid data, you check the return of the function you are using. With scanf it returns the number of successful conversions or EOF if failure occurs before the first conversion takes place. So when taking input with scanf you always check that the return matched the number of conversions you specify in your format-string. With "%d" -- one conversion to int will take place. So to validate the input, you use:

         if (scanf ("%d", &array_ptr[index]) != 1) {
            fputs ("error: invalid integer input.\n", stderr);
            return NULL;
        }

(which just say if the return from scanf() isn't 1 -- handle the error -- which is to return failure (or NULL) in this case)

Finally in main(), you will validate the return of record_array is not NULL before using the allocated block in print_array(), e.g.

    if ((array = record_array (&size))) {   /* validate record_array succeeds */
        print_array (array, &size);         /* print array */
        free (array);                       /* free array */
    }

(the comparison is shorthand for: if ((array = record_array (&size)) != NULL) {.... You could have done the assignment separately, e.g. array = record_array (&size); and then if (array != NULL) {... so long as you validate the return :)

Making those corrections (and providing a space in the prompt to separate the prompt and the input) you would have:

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

int *record_array (int *size_ptr);
void print_array (int *array_ptr, int *size_ptr);


int *record_array (int *size_ptr)
{
    int *array_ptr = malloc (*size_ptr * sizeof *array_ptr);

    if (!array_ptr) {   /* validate EVERY allocation */
        perror ("malloc-array_ptr");
        return NULL;
    }

    for (int index = 0; index < *size_ptr; index++)
    {
        printf ("Enter element at index %d: ", index);
        if (scanf ("%d", &array_ptr[index]) != 1) {
            fputs ("error: invalid integer input.\n", stderr);
            return NULL;
        }

    }
    return array_ptr;
}

void print_array (int *array_ptr, int *size_ptr)
{
    for (int index = 0; index < *size_ptr; index++)
        printf ("%d ",array_ptr[index]);

    putchar ('\n');     /* tidy up with newline */
}

int main()
{
    int size = 0;
    int *array = NULL;  /* you need a pointer to hold the address of your array */

    printf("How many elements do you want? ");
    if (scanf("%d", &size) != 1) {          /* validate EVERY input */
        fputs ("error: invalid integer input.\n", stderr);
        return 1;
    }

    if ((array = record_array (&size))) {   /* validate record_array succeeds */
        print_array (array, &size);         /* print array */
        free (array);                       /* free array */
    }
}

Example Use/Output

$ ./bin/readarrayfunc
How many elements do you want? 5
Enter element at index 0: 1
Enter element at index 1: 2
Enter element at index 2: 3
Enter element at index 3: 4
Enter element at index 4: 5
1 2 3 4 5

Note also with declarations the '*' goes with the variable, not the type. Why? Readability. Look at:

int* a, b, c;

That certainly does not declare 3-pointers to int, it declares one pointer to int and two integers:

int *a, b, c;

makes that clear.

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • Sure, what point are you stuck on and I'm happy to explain it further. Also a few links that provide basic discussions of pointers may help. [Difference between char *pp and (char*) p?](https://stackoverflow.com/a/60519053/3422102) and [Pointer to pointer of structs indexing out of bounds(?)...](https://stackoverflow.com/a/60639540/3422102) – David C. Rankin May 31 '20 at 09:11
  • I'm stuck at this part ` if (scanf("%d", &size) != 1) { /* validate EVERY input */ fputs ("error: invalid integer input.\n", stderr); return 1; }` – default-303 May 31 '20 at 09:13
  • Sure, I'll edit and expand on the answer, but the basic idea in validation in (1) do something that has potential for failure (2) check that it worked or (3) handle the error. That is what is going on in each validation. – David C. Rankin May 31 '20 at 09:14
  • @Kakshipth - see if the addition helps. If not, let me know what point you are still unlear on and I'll try again. Also note from `main()` the use of `return 1;` is equivalent to using `exit (EXIT_FAILURE);` In C there are two exit codes defined for returning to the shell, `EXIT_SUCCESS` is `0` and `EXIT_FAILURE` is `1`. That is why `1` is being returned from `main()` in the event `scanf()` fails. – David C. Rankin May 31 '20 at 09:21
  • 1
    @RavinderSingh13 no expert, but I started coding in C/C++ back in the mid 80's (when C++ wasn't much more than a super-set of C) and in FORTRAN -- thankfully after floppy disks were in use and the punch-card readers were all but gone. We all remember 8" floppies right? So while no expert, I usually know what part of the standard to look at to find an answer or two `:)` – David C. Rankin Jun 11 '20 at 18:56
  • @DavidC.Rankin, honestly you are one of the nice, gentle and well explainer person on SO I always love sharing and learning with you. Btw on a lighter note I was born in late eighties :) :) while you was coding already so I love learning from senior folks always :) (these are temp comments I always remove them once message is conveyed) cheers sir. – RavinderSingh13 Jun 11 '20 at 18:59
  • I do. I'm not a senior citizen yet! But when your kids are on college -- it's not far off... – David C. Rankin Jun 11 '20 at 19:55