Correctly passing an array from a function - c

I have some code to generate an array of size [user_input] in a function called array_generator, using size of array from scanf in main(), and then filling it with the numbers 0 to user_input (0, 1, 2, 3, if user input is 4). The array fills correctly as printf prints
`The array contains the value 1`
`The array contains the value 2`
`The array contains the value 3`, etc.
However when I pass the array to main and printf the array values I get equal statements filled with garbage numbers. I'm also 90% sure I have been passing the arrays and pointers incorrectly (new to them).
The code is below:
#include <stdio.h>
int *array_generator(int number_songs);
int main(void)
{
int input;
int *p;
int i;
int x;
printf("Enter number of songs wanted in random playlist: ");
scanf("%d", &input);
p = array_generator(input);
x = *p;
for (i = 0; i < input; i++)
{
printf("The array contains the values %d\n", x);
}
return 0;
}
int *array_generator(int n)
{
int a[n];
int *p;
int i;
for (i = 0; i < n; i++)
{
a[i] = i;
printf("The array contains the values %d\n", i);
}
return p = &a[n];
}

One simple solution is to define an array which is bigger than the largest list of songs reasonably possible. For example, since you print every entry, more than a few hundred are not reasonable. On a modern computer space is abundant. You would have a define for the max size on top of the prog, or later in some header:
#define MAX_SONGLIST_LEN 1000
The array can be global, or it can be static inside the function. Let's make it static because you want the function to return the address.
The change is minimal. Just say
static int a[MAX_SONGLIST_LEN];
You may want to change the loop and check for the max length as well:
for (i = 0; i < input && i < MAX_SONGLIST_LEN; i++)
inside array_generator() and main(). You also may want to inform your users about the maximum, and catch numbers which are too large. (You don't do any error handling of user input anyway -- what happens if the user enters a letter instead of a number? Look into the return value of scanf().)
The static array's life time is the lifetime of the program. It will be initialized to all zeroes by the way. If you want to randomly initialize it look at the rand() function.

You are correct in that you are using pointers wrong. The code below preforms the function that you want...
#include <stdio.h>
void array_generator(int n, int arr[]) {
for (int i = 0; i < n; i++) {
arr[i] = i;//array values
//printf("The array contains the values %d\n", i);
}
}
int main() {
int input;
printf("Enter number of songs wanted in random playlist: ");
scanf("%d", &input);
int array[input];//declare array with length of input
array_generator(input, array);
for(int i=0; i<sizeof(array)/sizeof(array[0]); i++) {//input could also be used at the limit to the for loop
printf("%d", array[i]);
}
printf("\n");
return 0;
}
What you are doing is you are over complicating your code. The first thing you do is you create a function and try to make it return an array. This is not necessary. All you need to do is pass a pointer to the array and all edits to the array will be made on the same scope as the array was declared on.
You also mentioned that you want to find the size of an array. This can be done with array *a of any type and sizeof(a)/sizeof(a[0]). This works by returning the number of bytes used by the array divided by the number of bytes used by the first element in the array.
One more thing that you have that you don't need is x = *p;. when you do this, you are essentially doing this x=*p=array_gen(input);
More information on pointers in C can be found here.

Related

0 in The Array is Causing a Semantic Error. How to Overcome?

The question is to make a program to read an integer array from the user and pass it to a function that takes two arrays - the first array with the values obtained form the user and the second array as an empty array. The objective is to append the indices of the even numbers present in the original array to the empty array and return the number of even numbers present in the original array.
If the input was:
Enter number of elements: 5
Enter element [1]: 0
Enter element [2]: 1
Enter element [3]: 2
Enter element [4]: 3
Enter element [5]: 4
Then the output shows:
37945345.
which is a garbage value inside the empty array's first element.
This is the code:
#include <stdio.h>
int evenIndices(int origArr[], int emptyArr[]) {
int i = 0, j = 0;
int evenCount = 0;
while (origArr[i] != '\0') {
if (origArr[i] % 2 == 0) {
emptyArr[j] = i;
evenCount ++;
j++;
}
i++;
}
return evenCount;
}
int main() {
int numOfElts;
printf("Enter number of elements: ");
scanf("%d", &numOfElts);
int arr[numOfElts];
for (int i = 0; i < numOfElts; i++) {
printf("Enter element [%d]: ", i + 1);
scanf("%d", &arr[i]);
}
arr[numOfElts] = '\0';
int indexArr[numOfElts];
int evenCount = evenIndices(arr, indexArr);
printf("There are %d even numbers. \n", evenCount);
printf("*** Indices With Even Numbers in Original Array *** \n");
for (int i = 0; i < evenCount - 1; i++) {
printf("%d, ", indexArr[i]);
}
printf("%d. \n", indexArr[evenCount - 1]);
return 0;
}
This code works for all numbers in array except for 0. If 0 is entered, the function assumes that it is same as '\0' and quits the loop. What is the solution to this?
For starters this assignment statement
arr[numOfElts] = '\0';
invokes undefined behavior because there is an access of memory beyond the array because the valid range of indices for the array is [0, numOfElts).
Remove this statement.
The function evenIndices should be declared like
int evenIndices( const int origArr[], int n, int emptyArr[]);
That is you need to pass the number of elements in the original array. And the first parameter should be declared with the qualifier const because the passed array is not changed within the function.
The condition in the while loop
while (origArr[i] != '\0') {
does not make a sense. The user can enter 0 as a valid value of the source array.
One of these variables, j and evenCount, is redundant.
The function can be defined the following way
int evenIndices( const int origArr[], int n, int emptyArr[])
{
int evenCount = 0;
for ( int i = 0; i < n; i++ )
{
if ( origArr[i] % 2 == 0 ) emptyArr[evenCount++] = i;
}
return evenCount;
}
And the function is called like
int evenCount = evenIndices( arr, numOfElts, indexArr );
Pay attention to that if the function returns 0 then this code snippet
for (int i = 0; i < evenCount - 1; i++) {
printf("%d, ", indexArr[i]);
}
printf("%d. \n", indexArr[evenCount - 1]);
will produce an invalid output. There is no need to split the for loop. Instead write
for (int i = 0; i < evenCount; i++) {
printf("%d, ", indexArr[i]);
}
putchar( '\n' );
You are trying to use '\0' as a sentinel. Thus you cannot have '\0' or '0' ('\0' is 0) as a valid value. I would recommend that you use INT_MIN as the sentinel. Then your range of acceptableinputs will be 2^32-1 to -(2^32-1) and that will be nice.
"pass it to a function that takes two arrays"
To pass arrays, the size information must be included in some way as array parameters in C decay into simple pointers, losing all array size information. The following method makes use of the VLA parameter format, i.e. define the size(s) of the array(s) you are passing prior to the array(s) themselves in the prototype...
Change the prototype from:
int evenIndices(int origArr[], int emptyArr[]);
To:
int evenIndices(int x, int y, int origArr[x], int emptyArr[y]);
Then pass it as:
int evenCount = evenIndices(numOfElts, numOfElts, arr, indexArr);
Or, because the size of both arrays sizes in this case is the same, you can define a single int x in the prototype,
int evenIndices(int x, int origArr[x], int emptyArr[x]);
then pass it as:
int evenCount = evenIndices(numOfElts, origArr, emptyArr);

Unexpected output of a growing dynamic array

I am attempting to create a dynamic array that will grow in size if needed, as I don't know how large the array will actually be. My code seems to work until the 8th element of the array where I start to see very large incorrect values that I did not enter. Not sure why this is happening.
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char** argv)
{
int val;
int userInput;
int* arr;
int size = 1;
int arrIndex = 0;
arr = (int*) malloc(sizeof(int) * size);
/* prompt the user for input */
printf ("Enter in a list of numbers to be stored in a dynamic array.\n");
printf ("End the list with the terminal value of -999\n");
/* loop until the user enters -999 */
scanf ("%d", &val);
while (val != -999)
{
if (arrIndex >= size)
{
size++;
}
arr[arrIndex] = val;
arrIndex++;
/* get next value */
scanf("%d", &val);
}
int j = 0;
for(j = 0; j < size ; j++)
{
printf("%d \t", arr[j]);
}
}
The size of the array remains 1 and doesn't increase while incrementing size variable.
Your code worked until 8th element because adjacent memory after the array upto 7th element must be free.
In C array index out of bound is not checked and it is programmers responibility.
if you want to increase or decrease size of array you can use realloc inside while loop:
arr=(int*)realloc(arr,sizeof(int)*size);
Also Correct this if condition in your code initially arrayindex is 0 and size is 1 which results in false.
if (arrIndex >= size)
{
size++;
}

Binary search not returning the position

this code is used to create an array filled with 10 random integers. It sorts the array and then inputs the array into a binary search function. I do not get the position of where my search key is positioned.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int binary_search(int array[], int search, int strt, int ending)
{
int middle;
middle = (strt + ending)/2;//splitting the array in half to compare the search key
if (search > array[middle]){binary_search(array, search, middle + 1, ending);}
else if(search == array[middle])
{
printf("Your search key is indicated in %d position the array Ferrari\n", middle + 1);
return middle;
}
else{binary_search(array, search, strt, middle -1);}
return -1;
}
int main()
{
srand(time(NULL));//random number seed generator
int Ferrari[10];
int size = 10;
int selection;
int temporary = 0;//I'm using this variable to store
//the value returned from linear_search()
int start = 0;
int end;
int i;
//this is to generate a random number between 0 and 101
for(int i=0; i<10; i++) {Ferrari[i] = rand() % 100 + 1;}
//printing the initial array
printf("\nThe array Ferrari consists of -> ");
for(int i=0; i<10; i++){printf("%d, ", Ferrari[i]);}
//--------------------------SORTING--------------------------------------------
for(int f = 0; f < (size - 1); f++)
{
for(int kk = 0; kk < (size - 1 - f); kk++)
{
if(Ferrari[kk] > Ferrari[kk +1])
{
int Te_mP;
Te_mP = Ferrari[kk + 1];
Ferrari[kk+1] = Ferrari[kk];
Ferrari[kk] = Te_mP;
}
}
}
//----------------------------------------------------------------------------
//printing the array after it has been sorted
printf("\n");
printf("\nThe sorted array Ferrari consists of -> ");
for(int i=0; i<10; i++){printf("%d, ", Ferrari[i]);}
start = 0;
end = i -1;
//this will be used to implement the searching algorithm
printf("\n\n");
printf("Please enter a number to test if it is included in the array or not\n");
scanf("%d", &selection);
temporary = binary_search(Ferrari, selection, start, end);
return 0;
}
I keep getting the answer that the search key is positioned in ``0 of array Ferrari. How do I resolve this?
Please let me know what I'm doing wrong over here. Much appreciated.
Look at this line
end = i - 1;
Where is i initialized?
In your loop you have
for(int i=0........
Note by giving int i=0 it means you are creating a new variable i within the for block. So this doesn't alter your original i variable declared at the top. Try using end = size - 1 or it's a best practice to define a constant for this purpose.
#define ARR_SIZE 10
in loop
for(i=0; i<ARR_SIZE;i++)
Then initialize end = ARR_SIZE -1;
And one more thing in your binary_search function is that you don't handle the case when the key is not present in the array.
Something like
if(end==start && array[end] != search)
return -1;
This checks when the search space has only one element and that is not your search element, it means it doesn't exist so we return -1.
Hope this helps
The problem is occurring because you are using uninitialised variable i here:
end = i -1;
Note that the scope of variable i declared in loop init clause is different from the scope of variable i declared in function block.
for(int i=0; i<10; i++){
^^^^^^^
// The scope of i declared in loop init clause is limited to the loop.
To fix the problem, you can use the i declared at function block scope as the loop variable, like this
for(i=0; i<10; i++){
Now, after the loop finishes, the variable i will hold its last value until it's value explicitly modify. But using i to identify the size of array down the code may cause several problems as it is not tightly coupled with the size of array and i may be get modified by other part of code. So, it is not the right idea to use i to identify the size of array.
Since, you are having a variable size which hold the size of array Ferrari, you can do:
end = size - 1;
No need to have another variable to keep the track of size of array. The problem with this is that you have to keep updating the size whenever you change the array size. An alternative of this would be to use a macro to define the array size.
The most appropriate way to set the end of array would be:
end = (sizeof(Ferrari) / sizeof(Ferrari[0])) - 1;

C - Passing a 3D arrays of chars to a function

I'm trying to write a program that analyzes a (3 x 4) matrix of strings provided by the user. Ultimately, it needs to output the longest string present in the matrix, along with that string's length.
My program seems to read the input correctly, as judged its success in echoing back the input strings, but it does not correctly output the longest word. I'm sure I'm committing some kind of pointer-related error when I pass the value of longest word, but I do not have any idea how to solve it.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define M 4
#define N 5
#define MAX_DIM 20
void findMAX(char matrice[N][M][MAX_DIM]) {
char maxr;
int index;
int i, j, it;
index = 0;
maxr = *(*(*(matrice+0)+0)+MAX_DIM);
for (i = 0; i < N-1; i++) {
for (j = 0; j < M-1; j++) {
if (index < strlen(matrice[i][j])) {
index = strlen(matrice[i][j]);
// I save the longer line's value
it = i;
// I save the maximum's value
maxr = *(*(*(matrice+i)+j)+MAX_DIM);
}
}
}
printf ("The MAX is: -/%s/- and it's long: -/%d/- \n", maxr, index);
printf ("It is content in the: %d line, which is: \n", it);
for (j = 0; j < N-1; j++) {
printf("%s ", matrice[it][j]);
}
}
void leggi(char matrice[N][M][MAX_DIM]) {
int i, j;
for (i = 0; i < N-1; i++) {
for (j = 0; j < M-1; j++) {
printf ("Insert the element matrix [%d][%d]: ", i, j);
scanf ("%s", matrice[i][j]);
fflush(stdin);
}
}
}
void stampa(char matrice[N][M][MAX_DIM]) {
int i, j;
printf("\n(4 x 3) MATRIX\n");
for (i = 0; i < N-1; i++) {
for (j = 0; j < M-1; j++) {
printf("%s ", matrice[i][j]);
}
printf("\n\n");
}
}
int main(int argc, char *argv[]) {
char matrix[N][M][MAX_DIM]; //Matrix of N*M strings, which are long MAX_DIM
printf("************************************************\n");
printf("** FIND THE LINE WITH THE MAXIMUM ELEMENT **\n");
printf("** IN A (4 x 3) MATRIX **\n");
printf("************************************************\n");
printf ("Matrix Reading & Printing\n");
leggi (matrix);
stampa (matrix);
findMAX(matrix);
return 0;
}
First of all to address some misconceptions conveyed by another answer, consider your 3D array declared as
char matrix[N][M][MAX_DIM];
, where N, M, and MAX_DIM are macros expanding to integer constants.
This is an ordinary array (not a variable-length array).
If you want to pass this array to a function, it is perfectly acceptable to declare the corresponding function parameter exactly the same way as you've declared the array, as indeed you do:
void findMAX(char matrice[N][M][MAX_DIM])
But it is true that what is actually passed is not the array itself, but a pointer to its first element (by which all other elements can also be accessed. In C, multidimensional arrays are arrays of arrays, so the first element of a three-dimensional array is a two-dimensional array. In any case, that function declaration is equivalent to both of these:
void findMAX(char (*matrice)[M][MAX_DIM])
void findMAX(char matrice[][M][MAX_DIM])
Note in particular that the first dimension is not conveyed. Of those three equivalent forms, I find the last clearest in most cases.
It is quite odd, though, the way you access array elements in your findMAX() function. Here is the prototypical example of what you do:
maxr = *(*(*(matrice+i)+j)+MAX_DIM);
But what an ugly and confusing expression that is, especially compared to this guaranteed-equivalent one:
maxr = matrice[i][j][MAX_DIM];
Looking at that however, and it how you are using it, I find that although the assignment is type-correct, you are probably using the wrong type. maxr holds a single char. If you mean it to somehow capture the value of a whole string, then you need to declare it either as an array (into which you will copy strings' contents as needed), or as a pointer that you will set to point to the string of interest. The latter approach is more efficient, and I see nothing to recommend the former for your particular usage.
Thus, I think you want
char *maxr;
... and later ...
maxr = matrice[0][0];
... and ...
maxr = matrice[i][j];
That sort of usage should be familiar to you from, for example, your function stampo(); the primary difference is that now you're assigning the expression to a variable instead of passing it directly to a function.
And it turns out that changing maxr's type that way will correct the real problem here, which #AnttiHaapala already pointed out in comments: this function call ...
printf ("The MAX is: -/%s/- and it's long: -/%d/- \n", maxr, index);
requires the second argument (maxr) to be a pointer to a null-terminated array of char in order to correspond to the %s directive in the format string. Before, you were passing a single char instead, but with this correction you should get mostly the expected result.
You will probably, however, see at least one additional anomaly. You final loop in that function has the wrong bound. You are iterating with j, which is used as an index for the second dimension of your array. That dimension's extent is M, but the loop runs to N - 1.
Finally, I should observe that it's odd that you allocate space for a 5 x 4 array (of char arrays) and then ignore the last row and column. But that's merely wasteful, not wrong.
Try something like this:
void findMAX(char matrice[N][M][MAX_DIM]){
// char maxr
char maxr[MAX_DIM];
int index;
int i, j, it;
index = 0;
// maxr = *(*(*(matrice+0)+0)+MAX_DIM);
strncpy(maxr, *(*(matrice+0)+0), MAX_DIM);
for (i = 0; i < N-1; i++)
{
for (j = 0; j < M-1; j++)
{
if (index < strlen(matrice[i][j]))
{
index = strlen(matrice[i][j]);
it = i;
// maxr = *(*(*(matrice+i)+j)+MAX_DIM);
strncpy(maxr, *(*(matrice+i)+j), MAX_DIM);
}
}
}
printf ("The MAX is: -/%s/- and it's long: -/%d/- \n", maxr, index);
printf ("It is content in the: %d line, which is: \n", it);
// for (j = 0; j < N-1; j++){
for (j = 0; j < M-1; j++){
printf("%s ", matrice[it][j]);
}
}
It's possible to pass multi-dimensional arrays to C functions if the size of the minor dimensions is known at compile time. However the syntax is unacceptable
void foo( int (*array2d)[6] )
Often array dimensions aren't known at compile time and it is necessary to create a flat array and access via
array2D[y*width+x]
Generally it's easier just to use this method even if array dimensions are known.
To clarify in response to a comment, C99 allows passing of variable size arrays using the more intuitive syntax. However the standard isn't supported by Microsoft's Visual C++ compiler, which means that you can't use it for many practical purposes.

Array doesn't print in reverse in C using pointers

I am trying to make a program that takes 10 numbers as input and outputs them in reverse order using pointers in C.
#include<stdio.h>
#define N 10
int array[N]; //Global variable
int main(void) {
int j;
int i;
printf("Enter 10 numbers: ");
for (i=0;i<N;i++) {
scanf("%d",(array+(4*i))); //Works
}
for (j=N-1;j<0;j--) {
printf("%d",array[j]); //Doesn't print, using *(array+j*4) doesn't
//print also
}
printf("\n");
printf("%d\n",*(array)); //Works so scanf works
printf("%d\n",*(array+4)); //Works so scanf works
return 0;
}
I have tried a making a seperate function for the two for loops but still it doesn't work. I want to know WHY this for-loop doesn't print but the two printfs below it print.
EDIT:
My new code is
#include<stdio.h>
#define N 10
int array[N]; //Global variable
int main(void) {
int j;
int i;
printf("Enter 10 numbers: ");
for (i=0;i<N;i++) {
scanf("%d",(array+i)); //Works
}
for (j=N-1;j<0;j--) { //it is supposed to be j>=0 or j>0 WHY
printf("%d",array[j]); //Doesn't print, using *(array+j) doesn't
//print also
}
printf("\n");
printf("%d\n",*(array)); //Works so scanf works
printf("%d\n",*(array+1)); //Works so scanf works
return 0;
}
Thanks to all the posts, I have a better understanding of how indexing works in C now but the printf doesn't work still unless I change the for-loop conditions(see above). WHY doesn't it work with the initial conditions but with the latter conditions.
Whoa!
This:
scanf("%d",(array+(4*i))); //Works
is very wrong and is overwriting memory! Why are you multiplying the index? You don't need to do that, C can index by itself. It should just be:
scanf("%d", &array[i]);
You want the address of the i:th array member, so say that, don't beat around the bush with strange multiplications.
If you really want to be "using pointers", as mentioned in a comment, you can do so:
scanf("%d", array + i);
This works since array is a pointer to the first element of the array, and adding i to is a fully valid use of pointer arithmetic; C will compute the proper pointer, knowing the size of each int in the array.
Your array consists of 10 elements with type int (obviously). In expression array + i variable i is not an offset in bytes. It is an index of element. So when you read it like you do (scanf("%d",(array+(4*i)))) you basicly read array[0], array[4], array[8], array[12] (we're out of array bounds here already, it causes memory corruption and might cause crashes), etc. Elements array[1],[2],[3],[5], etc. are uninitialized. That's why your code doesn't work :)
UPDATE:
And #shilong-liu's note about array indices is important, too. I didn't notice it.
for (j=N-1;j<0;j--) {
printf("%d",array[j]); //Doesn't print, using *(array+j*4)
}
the for loop is not right. The correct one is that
for (j = N - 1; j > 0; j--)
I guess since the pointer used is of type int, you assume that you have to multiply i by 4 because depending on the compiler int is 4 bytes. I guess if you really care only about the output, then you could do it the way you did with reverse iteration.
What you have to do has been already mentioned by the others so I will give you my solution for actually swapping the pointers memory wise and you could choose from the given solutions:
#include<stdio.h>
#define N 10
int array[N]; //Global variable
int main(void) {
int j;
int i;
printf("Enter 10 numbers: ");
for (i=0; i<N; i++) {
scanf("%d", (array + i));
}
for (left = 0; left < N / 2; left++)
{
int right = N - left - 1;
int temporary = array[left];
array[left] = array[right];
array[right] = temporary;
}
for (i=0; i<N; i++) {
printf("%d", (array + i));
}
return 0;
}
I have been programming for algorithmic contests so you could trust me.

Resources