How to make a function to read an array in c? [duplicate] - c

This question already has an answer here:
Dynamic memory access only works inside function
(1 answer)
Closed 5 years ago.
I have to write function to read the array length and the array and make that array able to be used in other functions.
I have read many things about pointers but I didn`t find an answer to my question.
Here is my code.
int readArray(int *ar, int *pointer){
int i, length;
scanf("%d", &length);
ar = (int *) malloc(length * sizeof(int));
for(i = 0; i < length; i++){
scanf("%d", pointer + i);
}
return length;
}
void printArray(int *pointer, int length){
int i;
for(i = 0; i < length; i++){
printf("%d ", *(pointer + i));
}
}
int main(){
int *pointer, *ar, length;
pointer = ar[0];//Here I get the warnings.
length = readArray(ar, pointer);
printArray(pointer, length);
return 0;
}
The warnings in codeblocks:
warning: assignment makes pointer from integer without a cast
and
warning: 'ar' is used uninitialized in this function [-Wuninitialized]|.
This question is different from this Dynamic memory access only works inside function because i have to read the array length in the readArray function. And for me, as a begginer, only little difference is a big difference.

I would consider with 2 options. One returns pointer to array and saves length as pointer and another returns length but accepts pointer to pointer as parameter.
Option 1: Return pointer of array and pass pointer to length parameter
This option will return pointer to allocated and filled array and length will be saved to pointer passed as parameter
int* readArray(int* length) {
int* arr;
//Scan for length
scanf("%d", length);
//Allocate memory
arr = (int *)malloc(...);
//Fill data
...
return arr;
}
and I will use it like this:
int length;
int *pointer;
pointer = readArray(&length);
printArray(pointer, length);
Option 2: Pass pointer to pointer to array and return length of array
int readArray(int ** ar) {
int length;
....
*ar = (int *)malloc(...);
...
return length;
}
Usage:
int* ar;
int length;
length = readArray(&ar);
printArray(ar, length);
I would go with this option.

You actually want this:
int readArray(int **ar) {
int i, length;
scanf("%d", &length);
*ar = (int *)malloc(length * sizeof(int));
for (i = 0; i < length; i++) {
scanf("%d", &(*ar)[i]);
}
return length;
}
void printArray(int *pointer, int length) {
int i;
for (i = 0; i < length; i++) {
printf("%d ", *(pointer + i));
}
}
int main() {
int *ar, length;
length = readArray(&ar);
printArray(ar, length);
return 0;
}
Variables are passed by value in C, included pointers. With your solution:
int readArray(int *ar, int *pointer){
int i, length;
scanf("%d", &length);
ar = (int *) malloc(length * sizeof(int));
for(i = 0; i < length; i++){
scanf("%d", pointer + i);
}
return length;
}
ar is a local variable to readArray and pointer will never get modified in main.
Consider this:
void foo(int bar)
{
bar = 123;
}
...
int a = 1;
foo(a);
// a won't contain 123 here

Related

dynamic arrays int printing problem - maybe not a valid memory cell

#include <stdio.h>
#include <stdlib.h>
int find_lenght(int *arrr){
int i = 0;
while(arrr[i] != '\0'){
i++;
}
return i;
}
void init_array(int *arrr){
arrr=(int*)malloc(1*sizeof(int));
printf("New element:");
int lenght = find_lenght(arrr);
scanf("%d", &arrr[lenght]);
printf("Lenght = %d\n",lenght);
printf("Array elements are:\n");
for(int i = 0; i <= lenght; i++) {
printf("%d,", arrr[i]);
}
}
void print_array(int *arrr){
printf("Array elements are:\n");
int lenght = find_lenght(arrr);
for(int i = 0; i == lenght; i++) {
printf("%d,", arrr[i]);
}
}
int main() {
int *arr = NULL;
init_array(arr);
print_array(arr);
}
I don't know what am i missing here.
My point is to fill in and then print dynamic array
Also my taught is it's not filling the way it should, so it hasn't anything to print.
Your arr pointer in main is never assigned because your init_array assign the address of the allocated memory (the return value of malloc) to the input parameter arrr, which is, a local variable.
You have mainly two solutions to properly achieve what you want to do. The first one (the better one in my point of view), by making your init_array returning the allocated memory address to be assigned:
int* init_array()
{
int* retval = (int*)malloc(1*sizeof(int));
// ...
return retval;
}
int main()
{
int *arr = init_array(); //< assign arr with returned value
}
Another way is to make your init_array function taking a pointer to a pointer, so the function can assign this pointer:
void init_array(int** arrr)
{
(*arrr) = (int*)malloc(1*sizeof(int));
// ...
}
int main()
{
int* arr = NULL;
init_array(&arr); //< pass reference to arr
}
You need to pass the pointer to pointer to int to change passed pointer. Your for loop is invalid in print function. You need also to set the sentinel value yourself.
size_t find_length(const int *arrr)
{
size_t i = 0;
if(arrr)
while(arrr[i]) i++;
return i;
}
void add_element(int **arrr, int element)
{
size_t length = find_length(*arrr);
int *tmp = realloc(*arrr, (length + 2) * sizeof(**arrr));
if(tmp)
{
*arrr = tmp;
(*arrr)[length] = element;
(*arrr)[length + 1] = 0;
}
}
void print_array(const int *arrr)
{
printf("Array elements are:\n");
size_t lenght = find_length(arrr);
for(size_t i = 0; i < lenght; i++)
{
printf("arrr[%zu] = %d\n", i, arrr[i]);
}
}
int main(void) {
int *arr = NULL;
add_element(&arr, 5);
add_element(&arr, 15);
add_element(&arr, 25);
add_element(&arr, 35);
print_array(arr);
}
https://godbolt.org/z/drKej3KT5
the array on your main function is still NULL. the better way to do is just call the print_array() function after you initialize it. you just simply put print_array(arrr) inside init_array() and after the for loop statement.
The line
int lenght = find_lenght(arrr);
may invoke undefined behavior, because find_length requires its argument to be a pointer to the first element of a null-terminated int array. However, the content of the memory pointed to by arrr is indeterminate, because it has not been initialized. Therefore, it is not guaranteed to be null-terminated.

Possible to run through a c-array inside a function with only one pointer as parameter?

I'm playing and learning a little with C, created an array and passed it to a function together with its size so I can run through the array and print all its elements (so I gave the function two parameters: the array itself and its size).
But now I like to do all that just by passing one parameter to the function. I got it working a little by using a pointer but I don't know how to stop because I don't have any information about arrays length, it only works in the code below because I put the array length inside the for loop. But how would that work in general if I didn't know the size and only passed one parameter to the function?
I thought it might somehow be possible to realize if a pointer points outside of the array I'm currently working with, but is that even doable? :S
void printArray(int *p){
for(int i=0; i<4; i++){
printf("%d ", *(p+i));
}
}
int main(){
int myArray[4] = {8,4,1,1};
int *p = myArray;
printArray(p);
return 0;
}
The only way to traverse a pointed-to array without a length parameter is if the array contains a distinct terminator value.
For example, a C-string is "NULL-terminated" array of char values. You can traverse a char* because you know
to test for the presence of the '\0' character, which has an integer value of 0.
As it applies to the code in your question, you could use -1 as a terminator value, like so:
void printArray(int *p){
while (*p != -1{
printf("%d ", *p++);
}
}
Note however, that doing this requires that there is some way to interpret a valid int value as
"invalid" for your purposes.
In the main, it's much easier and simpler to just pass the length of the array to the function.
In addition to other mentioned approaches I can offer other two:
1) You can pass the length of array as the first element (like works some containers in Pascal):
#include <stdio.h>
void print_array(int *arr)
{
int length = arr[0];
for (int index = 1; index <= length; ++index)
printf("%d ", arr[index]);
printf("\n");
}
int main()
{
int length = 10;
int *arr = malloc(sizeof(int) * length);
arr[0] = length;
for (int index = 1; index <= length; ++index)
arr[index] = index * index * index;
print_array(arr);
free(arr);
return 0;
}
2) You can create a struct for your array (like is is done for std::vector in C++ STD with class):
#include <stdio.h>
typedef struct Array
{
int size;
int *data;
} Array;
void print_array(Array *arr)
{
for (int index = 0; index < arr->size; ++index)
printf("%d ", arr->data[index]);
printf("\n");
}
int main()
{
int length = 10;
Array *arr = malloc(sizeof(Array));
arr->data = malloc(sizeof(int) * length);
arr->size = length;
for (int index = 0; index < length; ++index)
arr->data[index] = index * index * index;
print_array(arr);
free(arr->data);
free(arr);
return 0;
}

Returning a pointer to an array of structs

Let's say I have to create an array of structs that is allocated on the heap and return a pointer that points to this array of structs.
typedef struct Pair {
int x;
int y;
} Pair;
Pair** foo(int n, int m, int length)
{
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return &arr;
}
When I compile a program containing this function, it warns me that I am returning the address of a local variable. I assume this is because the pointer is initialised within the function (i.e. on the stack), therefore it counts as a local variable.
When I compile it, ignoring this warning, and run it anyway, the program crashes when the returned pointer is accessed.
I have tried allocating the pointer dynamically:
Pair** ptr = malloc(sizeof(**ptr));
ptr = &arr;
...
return ptr;
but the program still crashes when this pointer is accessed. How can I create this array within a function and return a pointer to this array so that it can be safely accessed?
This array is initialized on the stack but the pointer (arr) is a local variable, so the caller, main, cannot access it. You do not need to use the address of the pointer. You can access the array with the pointer itself.
Pair* foo(int n, int m, int length)
{
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return arr;
}
If you want an array of structs, the code:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x;
int y;
} Pair;
static Pair* foo(int n, int m, int length) {
Pair* arr = malloc(sizeof(*arr) * length);
for (int i = 0; i < length; ++i) {
arr[i].x = n++;
arr[i].y = m++;
}
return arr;
}
int main(void) {
Pair *z = foo(111, 222, 3);
for (int i = 0; i < 3; ++i)
printf("z[%d]= { %d, %d }\n", i, z[i].x, z[i].y);
free(z);
return 0;
}
gives the output:
z[0]= { 111, 222 }
z[1]= { 112, 223 }
z[2]= { 113, 224 }
If you want an pointer to an array of structs, you can change your function signature from Pair** to be Pair*.
If you still want an pointer to an array of pointers, then allocate memory for a Pair struct for each index of arr.
for(int i = 0; i < length; ++i){
arr[i] = malloc(sizeof(Pair));
...
}
Instead of returning &arr, you can declare arr as
Pair** arr = malloc(sizeof(Pair*) * length);
Because arr is a local variable, it will be free when foo end. So you don't have access for arr after. To solve this you should declare array pointer in heap:
Pair** foo(int n, int m, int length)
{
Pair ** arr = (Pair**)malloc(sizeof(Pair*));
*arr = malloc(sizeof(Pair) * length);
for (int i = 0; i < length; ++i) {
(*arr)[i].x = n++;
(*arr)[i].y = m++;
}
return arr;
}

How to return an array from a function with pointers

i'm trying to figure out how to return an array from a function in the main().
I'm using C language.
Here is my code.
#include <stdio.h>
int *initArray(int n){
int i;
int *array[n];
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
main(){
int i, n = 5;
int *array[n];
array[n] = initArray(n);
printf("Here is the array: ");
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
printf("\n\n");
}
And this is the errors the console gives me:
2.c: In function ‘initArray’:
2.c:8:13: warning: assignment makes pointer from integer without a cast [enabled by default]
array[i] = i*2;
^
2.c:11:3: warning: return from incompatible pointer type [enabled by default]
return array;
^
2.c:11:3: warning: function returns address of local variable [-Wreturn-local-addr]
2.c: In function ‘main’:
2.c:23:4: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d ", array[i]);
^
It's impossible!
I hate being a noob :(
If you could help, with explanations, I would appreciate! :D
Edit: iharob's answer is better than mine. Check his answer first.
Edit #2: I'm going to try to explain why your code is wrong
Consider the 2nd line of main() in your question:
int *array[n];
Let's try to read it backwards.
[n]
says we have an array that contains n elements. We don't know what type those elements are and what the name of the array is, but we know we have an array of size n.
array[n]
says your array is called array.
* array[n]
says you have a pointer to an array. The array that is being pointed to is called 'array' and has a size of n.
int * array[n];
says you have a pointer to an integer array called 'array' of size n.
At this point, you're 3/4 way to making a 2d array, since 2d arrays consist of a list of pointers to arrays. You don't want that.
Instead, what you need is:
int * array;
At this point, we need to examine your function, initArray:
int *initArray(int n){
int i;
int *array[n];
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
The second line of initArray has the same mistake as the second line of main. Make it
int * array;
Now, here comes the part that's harder to explain.
int * array;
doesn't allocate space for an array. At this point, it's a humble pointer. So, how do we allocate space for an array? We use malloc()
int * array = malloc(sizeof(int));
allocates space for only one integer value. At this point, it's more a variable than an array:
[0]
int * array = malloc(sizeof(int) * n);
allocates space for n integer variables, making it an array:
e.g. n = 5:
[0][0][0][0][0]
Note:The values in the real array are probably garbage values, because malloc doesn't zero out the memory, unlike calloc. The 0s are there for simplicity.
However, malloc doesnt always work, which is why you need to check it's return value:
(malloc will make array = NULL if it isn't successful)
if (array == NULL)
return NULL;
You then need to check the value of initArray.
#include <stdio.h>
#include <stdlib.h>
int *initArray(int n){
int i;
int *array = malloc(sizeof(int) * n);
if (array == NULL)
return NULL;
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
int main(){
int i, n = 5;
int *array = initArray(n);
if (array == NULL)
return 1;
printf("Here is the array: ");
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
free(array);
printf("\n\n");
return 0;
}
You can't just return an array like that. You need to make a dynamically allocated array in order to do that. Also, why did you use a 2d array anyway?
int array[5];
is basically (not completely) the same as:
int * array = malloc(sizeof(int) * 5);
The latter is a bit more flexible in that you can resize the memory that was allocated with malloc and you can return pointers from functions, like what the code I posted does.
Beware, though, because dynamic memory allocation is something you don't wanna get into if you're not ready for tons of pain and debugging :)
Also, free() anything that has been malloc'd after you're done using it and you should always check the return value for malloc() before using a pointer that has been allocated with it.
Thanks to iharob for reminding me to include this in the answer
Do you want to initialize the array? You can try it like this.
#include <stdio.h>
void initArray(int *p,int n)
{
int i;
for(i = 0; i < n; i++)
{
*(p+i) = i*2;
}
}
void main(void)
{
int i, n = 5;
int array[n];
initArray(array,n);
printf("Here is the array: ");
for(i = 0; i < n; i++)
{
printf("%d ", array[i]);
}
printf("\n\n");
}
If you don't want to get in trouble learning malloc and dynamic memory allocation you can try this
#include <stdio.h>
void initArray(int n, int array[n]) {
int i;
for (i = 0 ; i < n ; i++) {
array[i] = i * 2;
}
}
int main() { /* main should return int */
int i, n = 5;
int array[n];
initArray(n, array);
printf("Here is the array: ");
for(i = 0 ; i < n ; i++) {
printf("%d ", array[i]);
}
printf("\n\n");
return 0;
}
as you see, you don't need to return the array, if you declare it in main(), and pass it to the function you can just modify the values directly in the function.
If you want to use pointers, then
#include <stdio.h>
int *initArray(int n) {
int i;
int *array;
array = malloc(n * sizeof(*array));
if (array == NULL) /* you should always check malloc success */
return NULL;
for (i = 0 ; i < n ; i++) {
array[i] = i * 2;
}
return array;
}
int main() { /* main should return int */
int i, n = 5;
int *array;
array = initArray(n);
if (array == NULL) /* if null is returned, you can't dereference the pointer */
return -1;
printf("Here is the array: ");
for(i = 0 ; i < n ; i++) {
printf("%d ", array[i]);
}
free(array); /* you sould free the malloced pointer or you will have a memory leak */
printf("\n\n");
return 0;
}

Filling array in C by using functions

Okay, so I am calling function fill_arrays like this:
fill_arrays(&data1, &data2, &size1, &size2);
fill_arrays looks like this:
void fill_arrays(int **data1, int **data2, int *size1, int *size2){
*size1 = get_size(*size1, 1);
*size2 = get_size(*size2, 2);
*data1 = malloc(*size1 * sizeof(int *));
*data2 = malloc(*size2 * sizeof(int *));
input_data(&data1, *size1, 1);
}
In input_data function I would like to assign some numbers to an array:
void input_data(int **data, int size, int index){
*data[5] = 5;
}
The problem is, I am completely lost with pointers... Maybe you can tell me how should I call function input_data in order to be able to assign some numbers to data array?
Assuming that input_data should set all array values to a known value, you could write
void input_data(int *data, int size, int value){
for (int i=0; i<size; i++) {
data[i] = value;
}
}
calling this like
input_data(*data1, *size1, 5); // set all elements of data1 to 5
The key point here is that you can use (*data1)[index] to access a particular array element and can pass your arrays as int* arguments.
I stumbled upon this question while doing a homework assignment and the answer doesn't strike me as entirely satisfactory, so I'll try to improve upon it.
Here is a small program that will establish an array of a user-defined size, fill it arbitrarily, and print it.
#include <stdio.h>
#include <stdlib.h>
void fill_array(int *array, int n)
{
int i;
for (i = 0; i < n; i++)
{
// fill array like [1, 2, 3, 4...]
array[i] = i+1;
}
}
void print_array(int *array, int n)
{
int i;
printf("[");
for (i = 0; i < n; i++)
{
if (i == (n-1))
printf("%d]\n", array[i]);
else
printf("%d, ", array[i]);
}
}
int main()
{
int n;
printf("Please enter a size for your array>");
scanf("%d", &n);
// dynamically allocate memory for integer array of size n
array = (int*) malloc (n * (sizeof(int)));
fill_array(array, n);
print_array(array, n);
return 0;
}
I hope this helps anyone who is learning C for the first time, or coming back to it after years away from the tried and true language, like me.
It seems you should also add int *array = NULL in order to get it working.

Resources