recording and printing arrays using pointers - c

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;
}

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.

Related

Am using realloc function here two times in a row and it doesn't seem to work , I use it once and it works completely fine can someone tell me why?

#include <stdio.h>
#include <stdlib.h>
char *ptr;
int n;
int main()
{
ptr = (char *)calloc(n, sizeof(char));
// First ID
printf("Enter the length of your employ ID\n");
scanf("%d", &n);
for (int i = 0; i <= n; i++)
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i++)
{
printf("%c", ptr[i]);
}
// Second ID
printf("Enter the size of new ID\n");
scanf("%d", &n);
ptr = (char *)realloc(ptr, n * sizeof(char));
for (int i = 0; i <= n; i++)
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i++)
{
printf("%c", ptr[i]);
}
// Third ID
printf("Enter the size of new ID\n");
scanf("%d", &n);
ptr = (char *)realloc(ptr, n * sizeof(char));
for (int i =0; i <=n; i++)
{
scanf("%c", &ptr[i]);
}
for (int i = 0; i <= n; i++)
{
printf("%c", ptr[i]);
}
return 0;
}
I tried to Get Ids of three people but the program doesnt work and after taking the input once it just exits : ( . It works fine when I use realloc once but not twice can someone explain why ?
it takes the input and then exits
The statement:
int n;
declares n at file scope. Objects declared at file scope have static storage duration and are always initialised. In the absence of an explicit initialization, they are implicitly initialised to zero.
From the C standard C11 6.7.9/10:
"... If an object that has static or thread storage duration is not
initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or
unsigned) zero;"
Accessing out of bounds memory:
Then:
ptr = (char *)calloc(n, sizeof(char));
allocates memory for 0 objects.
The calloc() function allocates memory for an array of nmemb elements
of size bytes each and returns a pointer to the allocated memory. The
memory is set to zero. If nmemb or size is 0, then calloc() returns
either NULL, or a unique pointer value that can later be successfully
passed to free().
On error, these functions return NULL. NULL may also be returned by a
successful call to malloc() with a size of zero, or by a successful
call to calloc() with nmemb or size equal to zero.
But you didn't check the return value of calloc.
Then, this statement:
scanf("%c", &ptr[i]);
tries to access memory that wasn't allocated, and thus invokes undefined Behaviour.
Off by one error:
You have allocated space for n elements, but the condition:
i <= n
tries to access n + 1 elements, which is memory out of bounds, memory you haven't allocated, memory that doesn't belong to you, and is thus undefined behaviour. (But that's irrelevant since you didn't allocate anything in the first place).
Regarding realloc:
The realloc() function returns a pointer to the newly allocated
memory, which is suitably aligned for any kind of variable and may be
different from ptr, or NULL if the request fails. If size was equal to
0, either NULL or a pointer suitable to be passed to free() is
returned. If realloc() fails the original block is left untouched; it
is not freed or moved.
Which means that if it fails and returns NULL, then ptr gets initialised with NULL and you lose all access to the original memory.
One solution is to use another pointer:
char *new = realloc(ptr, size);
if (!new) { /* if realloc failed */
/* deal with it however you wish */
}
/* If we got here, it means that we weren't bounded */
ptr = new;. /* Now ptr points to the new memory, if it didn't already */
new = 0; /* This avoids a dangling pointer */
/* some code relevant to ptr here */
free(ptr); /* For every allocation, there must be a call to free */
Side note: You shouldn't cast the result of malloc and family. It's redundant and may hide a bug. The void * returned by these functions is automatically promoted to the correct type.
Trailing newline:
scanf("%d", &n);
leaves a newline in the input buffer, which automatically gets read by subsequent calls to scanf, and you might never be prompted for input.
Instead of:
scanf("%c");
Use " %c" with a leading blank to skip optional white space:
scanf(" %c");
First of all, please note that you're using:
ptr = (char *)calloc(n, sizeof(char));
when n isn't explicitly initialized in file scope so it is automatically initialized to 0. So basically you overwrite a buffer of size 0 in:
for (int i = 0; i <= n; i++)
{
scanf("%c", &ptr[i]);
}
while exceeding the size allocated with i <= n which sould be i < n, that is probably why.
Second, you must free your memory allocation at the end using free and check allocation's success.
Third, when using strings, you might want to use scanf using %s, unless you have a specific reason.
A more clear and less error prone implementation may be:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size, times, i;
char *ptr;
printf("Enter the number of IDs to enter\n");
scanf("%d", &times);
for (i = 0; i < times; ++i) {
printf("Enter the size of new ID\n");
scanf("%d", &size);
if (size < 0) {
printf("Entered value is negative\n");
return size; // or any other error
}
// note the '+ 1' so we have a NULL terminating string
ptr = (char *)calloc(size + 1, sizeof(char));
if (ptr == NULL) {
printf("Error allocating ptr\n");
return -1; // or any other error
}
printf("Enter your ID\n");
scanf("%s", ptr);
printf("Your ID is: %s\n", ptr);
free(ptr);
}
return 0;
}
Hopefully I answered everything and didn't miss a thing (:

Initialize User defined parameters value for Array in C

I learned in the text book, that there are only a few ways you can initialize an array.
Method one:
int ary[5] = {1,2,3,4,5};
Method two:
int ary[] = {1,2,3,4,5};
But what if I want to input user defined values into the array. Would this code be ok? Can anyone teach me a better way to do this?
#include<stdio.h>
#include<conio.h>
int main()
{
int i, n;
printf("Enter array parameter: \n");
scanf("%d",&n);
int a[n];
int b[n];
for(i=0;i<n;i++)
{
printf("Enter value for array a[%d]: \n",i+1);
scanf("%d",&a[i]);
}
n -= 1;
for(i=0;i<=n;i++)
{
b[i]=a[n-i];
}
printf("Value of array b[] is: \n");
for(i=0;i<=n;i++)
{
printf("%d ",b[i]);
}
for(i=0;i<=n;i++)
{
printf("\narray b[%d] = %d ",i,b[i]);
}
getch();
}
int ary[5] {1,2,3,4,5};
This is not a valid array initialization. It should be
int ary[5] = {1,2,3,4,5};
Note the equal sign.
Other wise your array initialization is valid for C99 and above. Plain c would not allow the use of a variable to initialize the array size.
You have a large number of issue, Undefined Behavior being the most critical:
n -= 1;
for(i=0;i<=n;i++)
{
b[i]=a[n-i];
}
When i == n, you index one beyond the end of your b[] array. All arrays in C are zero-indexed, so your loop limits are 0 <= i < n. By using i<=n you loop one-too-many times.
You fail to check the return of any user-input. Try entering '"one"', or accidentally hitting 'r' instead of 4 and see what happens. You must check the return for every user-input and handle the error. What happens if the user enters 1, 2, 'r', 5? You must also empty stdin of any extraneous characters or they will bite you again on your next input.
Don't use conio.h. That makes your code 100% non-portable. You can use the functions in stdio.h for your needs.
That said, when you need to do repetitive tasks like taking integer input, write a short function to do it. You can write one that takes a pointer to the integer to fill, and a pointer to the prompt to display and returns 0 on success or -1 if the user cancels input by generating a manual EOF with Ctrl+d on Linux or Ctrl+z on windows. You can add a helper-function to empty stdin, e.g.
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int getint (int *n, const char *prompt)
{
int rtn;
for (;;) {
fputs (prompt, stdout);
rtn = scanf ("%d", n);
if (rtn == EOF) {
fputs (" (user canceled input)\n", stderr);
return -1;
}
else if (rtn == 0) {
fputs (" error: invalid integer input.\n", stderr);
empty_stdin();
}
else
break;
}
empty_stdin();
return 0;
}
The rest of your program to read an array in a[] and reverse it in b[] is simply:
int main (void) {
int i = 0, n;
if (getint (&n, "Enter array parameter: ") == -1)
return 0;
int a[n], b[n];
for (i = 0; i < n; i++) {
char buf[128];
sprintf (buf, "enter value for a[%d]: ", i+1);
if (getint (&a[i], buf) == -1)
return 0;
}
for (i = 0; i < n; i++)
b[i] = a[n - 1 - i];
puts ("\nvalue of array b[]:");
for (i = 0; i < n; i++)
printf (" %d", b[i]);
putchar ('\n');
#if defined (_WIN32) || defined (_WIN64)
getchar(); /* hold terminal open on windows - type any char, hit return */
#endif
}
Example Use/Output
All valid inputs:
$ ./bin/getarray
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]: 2
enter value for a[5]: 1
value of array b[]:
1 2 3 4 5
Errors in input:
$ ./bin/getarray
Enter array parameter: foo
error: invalid integer input.
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: four
error: invalid integer input.
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]: I'm getting tired of this game...
error: invalid integer input.
enter value for a[4]: 2
enter value for a[5]: 1
value of array b[]:
1 2 3 4 5
User cancels input:
$ ./bin/getarray
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]: (user canceled input)
Look things over and let me know if you have further questions.
As someone noted, the first way does not work in C. It is valid C++ though.
The second way int ary[] = {1,2,3,4,5}; works, the array ary is initialized with 5 items at compile time (before you even run the program). The memory is allocated on the stack.
You could also do it like this int ary[6] = {1,2,3,4,5};, where you specify what length you want the array to be. You can then access ary[5] and change it to whatever value you want (by default it is 0).
NOTE: ary[6] is out of bounds, since the array's elements go from 0 to 5.
In your code, you make use of something called Variable Length Arrays (VLAs), and as noted by Wikipedia, they are allocated with automatic storage duration on the stack. This means that when the function where you declared them ends, their life duration also ends (they are local to the function scope you declare them in). To understand why this is important, consider this piece of code:
int *func(int n) {
int v[n]; // variable length array
v[0] = 1;
v[1] = 2;
v[2] = 3;
return v; // this will not work, variable length arrays will be destroyed
// when the function they belong to goes out of scope
}
int main() {
int *v;
v = func(3); // when you will try to access the memory in v, it will be undefined
// behaviour (can seg fault, the memory is not yours anymore)
// print values in v
return 0;
}
To fix this issue, you need to use malloc defined in stdlib.h.
int *func(int n) {
int *v = malloc(sizeof(int) * n); // allocate memory for n elements
v[0] = 1;
v[1] = 2;
v[2] = 3;
return v; // this will now work
}
int main() {
int *v;
v = func(3); // this will work
// print values in v
free(v);
return 0;
}
The reason this works is because memory allocated using malloc is allocated on the heap, meaning it survives the whole duration of the program unless you deallocate it yourself (this means that you need to free the memory at the end using the function free).
Array initializing in C:
int ary[5] {1,2,3,4,5};
This is invalid syntax in c (this is valid in c++).
there is 3 ways to initialize c arrays:
with the curly brackets {} like you did (int ary[] = {1,2,3,4,5};)
iterating on the array elements one by one in for loop and initialize each one of them.
via : memset(void *str, int c, size_t n);, for padding the whole array in the same value. e.g. if i want to initialize the array with 0x0, then, memset call will lokks like: memset(arr, 0x0, sizeof(arr));
Regarding the you code:
for each scanf(..) in the code you have to check and validate scanf("%d",&n);, return/errors and user input in n before make any progress in your code. How you check? see later.
In you situation, it's good to limit the user input n and validating that n in defined range (N_min <= n <= N_max), rather than causing to huge array allocating on the stack in case n was set to maximum value by user!
if(scanf("%d",&n) == EOF){
/*errors ocuured*/
f_invoke_error_handling_rotuine();
}
In f_invoke_error_handling_rotuine(..), you can do what ever your code needs to perform, maybe abort() with error message, maybe setting default values to n...etc.
see reference for memset and scanf in man7.org:
scanf, memset
"Would this code be ok? Can anyone teach me a better way to do this?"
This code is okay from a syntactical perspective (you corrected the wrong initialization), but not portable since you use variable length arrays (VLAs) which might not supported by any implementation (They are provided my compiler extensions) and were only fully compliant to the C99 standard.
A better way to do this, is to use malloc() instead and allocate the memory for the array on the heap.
This also has the advantage that you can resize the array if you want to (make it larger f.e.) and free() the memory for the array when no longer needed.
Related stuff:
Is it a good idea to use C99 VLA compared to malloc/free?
Is there any overhead for using variable-length arrays?
When to use variable length array in C, but when a dynamic allocation?
int i, n;
printf("Enter amount of array elements: \n");
if (scanf("%d",&n) != 1)
{
fputs("Error at input!", stderr);
return EXIT_FAILURE;
}
int* a = malloc ( sizeof(*a) * n );
if (!a)
{
fputs("Error at allocation for a!", stderr);
return EXIT_FAILURE;
}
int* b = malloc ( sizeof(*b) * n );
if (!b)
{
fputs("Error at allocation for b!", stderr);
return EXIT_FAILURE;
}
for (i = 0; i < n; i++)
{
printf("Enter value for array a[%d]: \n", i);
if (scanf("%d", &a[i]) != 1)
{
fprintf(stderr, "Error at input for a[%d]!", i);
return EXIT_FAILURE;
}
}
...
free(a);
free(b);

passing argument 1 of 'functions' makes a pointer from an integer without a cast

i have to program a function which asks for an array and its size, and then prints its values. The main function must call 2 other functions, both of them take two arguments (an array and its size). The first one asks for values to fill the array, the second one prints each value.
Im new to C and to programming in general, so any tips and useful info is very welcomed. I know very little about pointers aswell.
void requestarray(int a[], int size){
int i;
for (i=0;i<size;i++)
{
printf("Insert value for %d position of the array\n",i);
scanf("%d\n",&a[i]);
}
}
void printarray(int a[], int size){
int i;
for (i=0;i<size;i++){
printf("%d\n",a[i]);
}
}
int main(void){
int size;
printf("Insert array length\n");
scanf("%d\n",&size);
int a[size];
requestarray(&a[size],size);
printf("\n");
printf("The array is\n");
printarray(&a[size],size);
return 0;
}
the program compiles but does not work. when i debug it using gdb, i place a breakpoint after
int a[size];
then i print the value of a and it returns an array with size length and random values (mainly big numbers). Then i place a breakpoint after
requestarray(&a[size],size);
(which should modify the values of the array) but it returns the same values as printed in the previous breakpoint.
if i change the code in the main function like this
requestarray(a[size],size);
printf("\n");
printf("The array is\n");
printarray(a[size],size);
the debugger gives me this warning
arreglo1.c: In function ‘main’:
arreglo1.c:33:14: warning: passing argument 1 of ‘requestarray’ makes pointer from integer without a cast [-Wint-conversion]
resquestarray(a[size],size);
^
arreglo1.c:8:6: note: expected ‘int *’ but argument is of type ‘int’
void requestarray(int a[], int size){
^~~~~~~~~~~~
arreglo1.c:36:16: warning: passing argument 1 of ‘imprimearreglo’ makes pointer from integer without a cast [-Wint-conversion]
printarray(a[size],size);
^
arreglo1.c:17:6: note: expected ‘int *’ but argument is of type ‘int’
void printarray(int a[], int size){
^~~~~~~~~~~~
scanf ("%d\n", &a[i]); is simply wrong (notice having to press Enter or provide more input than expected?) scanf will not process escape characters in that manner. Instead a literal '\n' causes scanf to disregard all whitespace forcing you to enter a non-whitespace character before it returns.
Whatever character you type to cause scanf to return does not match anything in your format string resulting in that character being left unread in stdin and will be used as your next attempted input.
That is why..., you must validate EVERY input by checking the return of each input function used. For instance in main(), e.g.
printf ("Insert array length: ");
if (scanf ("%d", &size) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
exit (EXIT_FAILURE);
}
and again in requestarray(), e.g.
for (i = 0; i < size; i++) {
printf ("Insert value for %d position of the array: ", i + 1);
if (scanf ("%d", &a[i]) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
exit (EXIT_FAILURE); /* handle error condition as desired */
}
}
Otherwise on a matching or input failure, scanf stops extracting characters from your input buffer (stdin here), the offending character is left in your input buffer just waiting to cause the same failure on your next call to scanf.
When you pass an array, you can simply use a pointer as the array is converted to a pointer on access, see: C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3). So you can write your function as simply:
void requestarray (int *a, int size)
{
int i;
putchar ('\n'); /* tidy up with newline before looping for input */
for (i = 0; i < size; i++) {
printf ("Insert value for %d position of the array: ", i + 1);
if (scanf ("%d", &a[i]) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
exit (EXIT_FAILURE); /* handle error condition as desired */
}
}
}
(note there is nothing wrong with passing int a[]. Also note how the code is spaced a bit wider making it easier to read (especially for older eyes..))
Putting it altogether you could do:
#include <stdio.h>
#include <stdlib.h> /* for EXIT_FAILURE define */
void requestarray (int *a, int size)
{
int i;
putchar ('\n'); /* tidy up with newline before looping for input */
for (i = 0; i < size; i++) {
printf ("Insert value for %d position of the array: ", i + 1);
if (scanf ("%d", &a[i]) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
exit (EXIT_FAILURE); /* handle error condition as desired */
}
}
}
void printarray (int *a, int size)
{
int i;
for (i = 0; i < size; i++){
printf ("%d\n", a[i]);
}
}
int main(void) {
int size;
printf ("Insert array length: ");
if (scanf ("%d", &size) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
exit (EXIT_FAILURE);
}
int a[size]; /* Variable Length Array of 'size' elements */
requestarray (a, size);
puts ("\nThe array is\n"); /* there is no convertion, puts will do */
printarray (a ,size);
return 0;
}
Example Use/Output
$ ./bin/inputarray
Insert array length: 5
Insert value for 1 position of the array: 1
Insert value for 2 position of the array: 2
Insert value for 3 position of the array: 3
Insert value for 4 position of the array: 4
Insert value for 5 position of the array: 5
The array is
1
2
3
4
5
Look things over and let me know if you have further questions.

Variable sized arrays and array pointer in C

I am doing coding exercise in HackerRank. In the Variable Sized Arrays exercise of C++, I tried to do it with C, but I couldn't get it right.
My code sometimes pass the simple test case 0, but sometimes not. The code was exactly the same but came out with different answer.
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int n, q;
scanf("%d%d", &n, &q);
int *p_arr[n];
if (n > 0) {
for (int i = 0; i < n; i++) {
int tmp;
scanf("%d", &tmp);
int tmp_arr[tmp];
p_arr[i] = tmp_arr;
for (int j = 0; j < tmp; j++) {
int value;
scanf("%d", &value);
p_arr[i][j] = value;
printf("%d ", p_arr[i][j]);
}
printf("\n");
}
}
if (q > 0) {
for (int i = 0; i < q; i++) {
int row, col;
scanf("%d%d", &row, &col);
printf ("%d %d\n", row, col);
int answer = p_arr[row][col];
printf("%d\n", answer);
}
}
return 0;
}
This was the wrong answer I got
1 5 4
1 2 8 9 3
0 1
21973
1 3
32764
I didn't know where the 21973 and 32764 came from.
This was the answer I expected
1 5 4
1 2 8 9 3
0 1
5
1 3
9
Sometimes I got the wrong answer, sometimes I got the correct. Why was that?
Thanks a lot!
Continuing from the comments, if the exercise involves a Variable Length Array, then it should be written in C because the C++ standard does not provide VLAs (and they have been made optional beginning in C11 after being added with C99)
The primary problem with your code (aside from a complete failure to allocate the inputs) is that it invokes Undefined Behavior because int tmp_arr[tmp] goes out of scope at the end of the for loop. What you assign with p_arr[i] = tmp_arr; no longer exists outside the loop because tmp_arr no longer exists. Any attempt to access a value after it has gone out of scope invokes Undefined Behavior, see Undefined, unspecified and implementation-defined behavior
Every time you handle input, you must validate the input succeeded and the value obtained is within a valid range. For instance both n and q must be positive values. Using scanf you could do (minimally)
if (scanf("%d%d", &n, &q) != 2 || n <= 0 || q <= 0) {
fputs ("error: invalid format or value.\n", stderr);
return 1;
}
The above validates that 2 inputs were received and that both are positive values.
In order to preserve the pointer assigned with p_arr[i] = tmp_arr;, tmp_arr must be an allocated type to handle an unknown tmp number of elements, or it must be declared outside the loop (and large enough to handle all anticipated values -- which given that tmp is read as input -- doesn't seem like the intended approach). You cannot declare tmp_arr static either as there would only be one instance and assigning it repeatedly to p_arr[i] would leave all elements of p_arr[i] pointing to the same place.
Simply allocate for tmp_arr and then the assignment to p_arr[i] will survive for the life of the program or until it is freed, e.g.
int *tmp_arr = calloc (tmp, sizeof *tmp_arr); /* allocate */
if (!tmp_arr) { /* validate every allocation */
perror ("calloc-tmp_arr");
return 1;
}
p_arr[i] = tmp_arr;
(note: calloc was used above to zero the new memory allocated. You can use malloc instead since the code assigns to each element)
Putting it altogether and adding (minimal) validation, you could do something similar to:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int n, q; /* validate EVERY input */
if (scanf("%d%d", &n, &q) != 2 || n <= 0 || q <= 0) {
fputs ("error: invalid format or value.\n", stderr);
return 1;
}
int *p_arr[n]; /* array of n-pointers to int */
for (int i = 0; i < n; i++) {
int tmp;
if (scanf("%d", &tmp) != 1 || tmp <= 0) { /* validate! */
fputs ("error: invalid input - tmp.\n", stderr);
return 1;
}
int *tmp_arr = calloc (tmp, sizeof *tmp_arr); /* allocate */
if (!tmp_arr) { /* validate every allocation */
perror ("calloc-tmp_arr");
return 1;
}
p_arr[i] = tmp_arr;
for (int j = 0; j < tmp; j++) {
int value;
if (scanf("%d", &value) != 1) { /* validate! */
fputs ("error: invalid input - value.\n", stderr);
return 1;
}
p_arr[i][j] = value;
printf ("%d ", p_arr[i][j]);
}
putchar ('\n'); /* no need to printf a single-character */
}
for (int i = 0; i < q; i++) {
int row, col; /* validate! */
if (scanf ("%d%d", &row, &col) != 2 || row < 0 || col < 0) {
fputs ("error: invalid input, row or col.\n", stderr);
return 1;
}
printf ("%d %d\n%d\n", row, col, p_arr[row][col]);
}
for (int i = 0; i < n; i++)
free (p_arr[i]);
return 0;
}
(Note: untested as no hackerrank input was provided)
Look things over and let me know if you have further questions.

How to dynamically take user input and store it into an integer array

I have an integer array like int a[50];. Now I want to store values entered by the user in the integer array as integers.
The problem is that I don't know the number of elements the user is going to input and hence I am unable to traverse the entire array.
So is there any method for the user to input the values dynamically and store it in the integer array and display it.
For this take a input from user for number of element to have in an array. Then malloc that memory and store the inputs in the array.
You can use realloc and make a specific input as end of the input
int readinput(int *value)
{
int status;
//function returns 0 on conversion -1 if exit keywoard entered
return status;
}
int value, *table = NULL,size = 0;
while (!readinput(&value))
{
table = realloc(table, (size++ + 1) * sizeof(int));
if (table == NULL)
{
break;
}
table[size] = value;
}
example converting function you can find here:
How to get Integer and float input without `scanf()` in c? in my answer
This code should work well, you can change BUFFER_SIZE to whatever you want, after these steps array will realloc to arr size + BUFFER_SIZE.
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 50
int main(void)
{
int * userInputBuffer = malloc(sizeof(int) * BUFFER_SIZE);
int userInput;
int counter = 0;
int reallocCounter = 1;
while ((scanf(" %d", &userInput)) == 1)
{
if ((counter % BUFFER_SIZE) == 0)
{
userInputBuffer = realloc(userInputBuffer, (reallocCounter++ + 1) * BUFFER_SIZE * sizeof(int));
}
userInputBuffer[counter++] = userInput;
}
for (int i = 0; i < counter; i++)
{
printf("User input #%d: %d\n", i + 1, userInputBuffer[i]);
}
free(userInputBuffer);
return 0;
}
The following solution uses the scanf() function with %d as format specifier. The while loop checks the return value so that it can detect if the conversion was successful. If anything other than a valid number is inputted the loop will break. A valid number is also beginning with space but not with any other characters.
The memory is allocated with malloc() and will be reallocated with realloc() each time the user entered a number. Note that there is no error checking about the reallocation this should be done with a temporary pointer like here.
Further this code will reallocate for every single number. You could also reallocate in bigger steps to avoid reallocation on every input. But this only matters if there is much data. In this case the speed improvement wouldn't matter.
After the memory is no longer needed you have to use free().
The user can type:
1<Enter>
2<Enter>
3<Enter>
any characters<Enter>
and will get:
Numbers entered:
1 2 3
as output.
Code:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
size_t idx;
int number;
size_t count = 0;
int* numberArr = malloc(sizeof(*numberArr));
printf("Enter each number separated by <Enter>,\n"
"to abort type any other character that isn't a number!\n");
while (scanf("%d", &number) == 1)
{
numberArr = realloc(numberArr, (count + 1) * sizeof(*numberArr));
numberArr[count] = number;
count++;
}
printf("\nNumbers entered:\n");
for (idx = 0; idx < count; idx++)
{
printf("%d ", numberArr[idx]);
}
printf("\n");
free(numberArr);
return 0;
}

Resources