2D arrays passed through functions in c - c

I'm having a problem with my program. I need my program to read from a text file, the first consists of the dimensions of the 2d array the rest is the contents of the array. I have coded the readWord function which reads from textfiles and it works but when i do anything on the main function with the array it crashes. Please could you help.
int main()
{
int num_it, cols, rows;
char** myworld;
num_it = readWorld(myworld,&cols, &rows);
myworld[1][2]='x';/*it crashes when i make this statement*/
}
int readWorld(char** world, int* width,int* height)
{
int result=0,i,cols=0,rows=0;
char buff[25];
FILE* file = fopen ("world.txt", "r");
fscanf(file, "%d %d %d\n", width, height, &result);
/*Dynamic allocation*/
world = (char**)malloc(*(height)* sizeof(char*));
for(i=0;i<*height;i++)
{
world[i] = (char*)malloc(*width*sizeof(char));
}
/*store data in array*/
while(fgets(buff, sizeof buff, file) != NULL)
{
if (strlen(buff) >1){
for(cols=0; cols<=(strlen(buff)); ++cols)
{
world[rows][cols] = buff[cols];
}
++rows;
}
}
fclose(file);
return result;
}

You need to allocate the memory for myworld in the actual caller!
What's happening here is that you are passing the pointer by value to the function.
The pointer value is changed by the function but that's not going to adjust the one in the caller.
Two options: use a triple indirection (ie pass a pointer to the the pointer) or allocate in the main sub. I prefer the latter, mainly because you can control the memory deallocation in a more symmetrical manner; even if you fixed this problem your code still has the memory leak.
What you're experiencing is undefined behaviour as you are attempting to access memory your program does not own.

Your myworld variable in main is never initialized and points to junk, so when you try to access it bad things happen. Think about why: you are passing a copy of the variable to readWorld. You correctly allocate memory inside there, and make the copy point to it, but the original pointer (in main) still points to whatever random location it pointed to before.
If you want the memory for it to be allocated inside the readWorld function and made accessible via the myworld variable in main then you must pass a pointer to myworld to readWorld; in other words, you must pass a triple pointer.
Try this:
int readWorld(char*** world, int* width,int* height)
{
char **tempworld = malloc(...);
// do whatever
*world = tempworld;
return result;
}
int main()
{
char **myworld = NULL;
readWorld(&myworld, ...);
return 0;
}

Related

How to pass an array with unknown 1-d dimension into function in C

I try something like below but all the time I have a segmentation fault.
I don't really want to use (e.g.) #define N 1000 and then declare int buffer[N].
Just in case..I'm not allowed to use any headers except stdio.h as well as dynamic memory.
void input (int *buffer, int *length);
int main()
{
int length, *buffer = NULL, *numbers = NULL;
input(buffer, &length);
}
void input(int *buffer, int *length) {
scanf("%d", length);
if (*length < 0) {
error = 1;
return;
}
for (int i = 0; i < *length; i++) {
scanf("%d", *buffer[i]);
}
}
How to pass an array with unknown 1-d dimension into function
In C, arrays cannot exist until their size is known.
There are other approaches though.
In C, code cannot pass an array to a function. some_function(some_array) converts the array some_array to the address of the first element of the array: &some_array[0]. That is what the function receives, a pointer, not an array. The original size information of the array is not passed, thus also pass the length to the function.
Sample:
Read desired length.
{
int length = 0;
scanf("%d", &length);
Form a variable length array, length >= 1.
if (length <= 0) {
return NULL;
}
int buffer[length];
Now call a function, passing the length and the address of the first element of the array.
// Do stuff with length and buf, like read data
foo1(length, buffer);
// foo1() receives the length & address of the first element of the array as an int *
// Do more stuff with length and buf, like write data
foo2(length, buffer);
}
At the end of the block }, buffer no longer available.
In C, you can't create an array if you can't know its size at compile time (or at least not in certain implementations and standards), so doing something like buffer[length] won't work (again at least not in certain implementations/standards).
What you need to do to make sure this works everywhere is to use a pointer (as I see you're trying to use here). However, what you're doing wrong here that causes your segfault with the pointers is you assign them the value of NULL. This also won't work due to how when you assign a pointer an arbitrary value, there is no memory allocated for the pointer (This applies for everything other than addresses of "regular" variables using the & operator and assigning other pointers that are checked to be OK). Your pointers are just pointing to address 0 and can't be used for anything.
What you need to do here to fix the pointers is to use dynamic memory allocation, so you can have a truly variable-sized array. Specifically, you need to use a function like malloc or calloc to allocate memory for the pointers so they are usable. In your case, using calloc and reading its documentation, we see that it takes 2 parameters: The number of elements it should allocate memory for and the size of each element. We also know that it returns a pointer to the starting address of the allocated memory and that in case of failure (which can only happen if you're out of memory), it returns NULL. Using this, we understand that in your case the call to calloc would be like this:
int *buffer = (int *) calloc(length, sizeof(int));
The sizeof() function returns the size of a data type in bytes. Here you allocated enough memory for the pointer to hold length integers (since you'll use it as an array you need enough memory for all the integers, you're not just pointing to 1 integer but storing all of them), and calloc is also noted to initialize every allocated element to 0, so you have an array of integers that are all initialized to 0 (Also note that type casting has been used to make sure the allocated memory block is appropriate for use with an integer array, you can read more about type casting in this small article from Tutorialspoint if you'd like). Then, after this has been allocated, you can start reading your integers into the array. The complete code looks like this:
void input (int *buffer, int *length);
int main() {
// NOTE: I don't see the numbers pointer used here, maybe remove it?
int length, *buffer, *numbers;
input(buffer, &length);
}
void input(int *buffer, int *length) {
scanf("%d", length);
if (*length < 0) {
// Consider printing the exact error here
error = 1;
return;
}
buffer = (int *) calloc(length, sizeof(int));
if (buffer == NULL) {
printf("Couldn't allocate memory for buffer\n");
error = 1;
return;
}
// Accessing the elements of an array doesn't need * and in fact * here can (and probably will) cause terrible things
for (int i = 0; i < *length; i++) {
scanf("%d", buffer[i]);
}
}
Also don't forget to call free() on the pointer after you're done using it to avoid memory leaks (in your case that'd be after the call to input()).
Hope this helped, good luck!
You cannot use arrays because their memory size must be known to the compiler at compile time. Also you can't use Variable Length Arrays because they are allocated at the point of declaration and deallocated when the block scope containing the declaration exits.
The solution to your problem might be to use malloc

how to free an allocated array in a function in c

If we were to use malloc() in main(), we could free() that dynamic memory allocation in main().
However, if we use malloc() in a different function
and we use that function in main(), where should we call free() to release the memory allocated in that function?
I.e., in the following source code:
#include <stdio.h>
#include <stdlib.h>
int * memory_allocate_function(int);
int main(void) {
int n=5; //length of array, 5 for example.
int *my_array;
my_array = memory_allocate_function(n);
return 0;
}
int * memory_allocate_function(int n) {
int i;
int *array;
array=(int *)malloc(n * sizeof(int));
if(array == NULL) {
printf("can not allocate memory.");
return NULL;
}
// I think i can't use "free(array);" in here.
// Because I need that array in main().
return array;
}
Is this the best way to do this?
Well after you are done working with it - free the dynamically allocated memory. But design wise - you can call the free in other function also to manage it properly. It really depends. There is no hard rule for that.
For example here you should return that pointer to allocated memory and then after using it in main you can free it in main().
So the structure would be something like
int* memory_allocate_function(int n)
{
int i;
int *array;
array = malloc(n*sizeof(int));
if(array == NULL)
{
printf("can not allocate memory.");
exit(0);
}
return array;
}
Then in main()
int main(void)
{
int n=5; //length of array, 5 for example.
int *arr = memory_allocate_function(n);
// work with arr
free(arr);
return 0;
}
But yes name the function properly - if you are going to use the name memory_allocate_function function then do that only - not any other major logic should be there. This helps create a good readable code.
Note one thing - here when you called the function and then you exited the function the only local variable that contains address of it, it's storage duration ended and you can never then access the memory you allocated. This is a case of memory leak. If you are determined that you won't return the pointer to memory from the function - then work with it (in the same function or different) and then free it (Before the scope of the function ends - notice not mentioning about where you would free it, you can do it in the same function and other function also).
I can't help mentioning few things:- 1) Dont cast the return value of malloc. 2) Check the return value of malloc - in case it is NULL you would like to handle it separately. 3) The recommended signature of main() is int main(void)
Memory should be freed when it's no longer needed.
Since the array would no longer be accessible after memory_allocate_function exits (since the array isn't returned or otherwise made accessible to the outside), it should be freed before memory_allocate_function exits.
void memory_allocate_function(int n){
int i;
int *array;
array = malloc(n*sizeof(int));
if (array == NULL) {
fprintf(stderr, "Out of memory.");
exit(1);
}
// ... use the array ...
free(array);
}
If you need to malloc memory in one function and free in another, you have to somehow carefully pass the pointer to that malloced memory from the point of malloc to the point where you want to free it.
This is your responsibility to preserve the pointer value and hand it from one function to another until it reaches the point of free. If you lose that value along the way, you'll have a memory leak. A memory leak is what you have now, since you are not passing that local array pointer anywhere.
There's no "one true way" to do it, since it depends on your specific intent. For example, you can return that pointer from memory_allocate_function, receive it main and eventually free it there
int *memory_allocate_function(int);
int main()
{
int n = 5;
int *arr = memory_allocate_function(n);
...
free(arr);
return 0;
}
int *memory_allocate_function(int n)
{
int *array = malloc(n * sizeof *array);
...
return array;
}

Returned array in C doesn't contain same values

I'm in the process of teaching myself C and I'm mistified as to what's causing the following issue: when I create an array in a method and return it as a pointer to the calling function, none of the content is correct. I've boiled down this problem to the following example:
char * makeArr(void){
char stuff[4];
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
printf("location of stuff:%p\n",stuff);
int i;
for(i = 0; i < 4; i++){
printf("%c\n",stuff[i]);
}
return stuff;
}
int main(void){
char* myarr;
myarr = makeArr();
int i;
printf("\n");
printf("location of myarr:%p\n", myarr);
for(i = 0; i < 4; i++){
printf("%c\n",myarr[i]);
}
}
The output returns the following:
location of stuff:0028FF08
a
b
c
d
location of myarr:0028FF08
Ä
ÿ
(
(a null character)
So I've verified that the locations between the two values are the same, however the values differ. I imagine that I'm missing some critical C caveat; I could speculate it's something to do with an array decaying into a pointer or a problem with the variable's scope, but and any light that could be shed on this would be much appreciated.
What you're attempting to do is return the address of a local variable, one that goes out of scope when the function exits, no different to:
char *fn(void) {
char xyzzy = '7';
return &xyzzy;
}
That's because, other than certain limited situations, an array will decay into a pointer to the first element of that array.
While you can technically return that pointer (it's not invalid in and of itself), what you can't do is dereference it afterwards with something like:
char *plugh = fn();
putchar (*plugh);
To do so is undefined behaviour, as per C11 6.5.3.2 Address and indirection operators /4 (my bold):
If an invalid value has been assigned to the pointer, the behaviour of the unary * operator is undefined.
Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
Having stated the problem, there are (at least) two ways to fix it.
First, you can create the array outside of the function (expanding its scope), and pass its address into the function to be populated.
void makeArr (char *stuff) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
int main(void) {
char myarr[4];
makeArr (myarr);
// Use myarr here
}
Second, you can dynamically allocate the array inside the function and pass it back. Items created on the heap do not go out of scope when a function exits, but you should both ensure that the allocation succeeded before trying to use it, and that you free the memory when you're finished with it.
char *makeArr (void) {
char *stuff = malloc (4);
if (stuff != NULL) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
return stuff;
}
int main(void) {
char *myarr;
myarr = makeArr();
if (myarr != NULL) {
// Use myarr here
free (myarr);
}
}
stuff[] only exists on the stack during function call, it gets written over after return. If you want it to hold values declare it static and it will do what you want.
However, the whole idea is fundamentally lame, don't do that in real life. If you want a function to initialize arrays, declare an array outside of the function, pass a pointer to this array as a parameter to the function and then initialize an array via that pointer. You may also want to pass the size of the array as a second parameter.
Since you're learning, a sample code is omitted intentionally.
Your array stuff is defined locally to the function makeArr. You should not expect it to survive past the life of that function.
char * makeArr(void){
char stuff[4];
Instead, try this:
char * makeArr(void){
char *stuff=(char*)calloc(4, sizeof(char));
This dynamically creates an array which will survive until you free() it.

C passing dynamic array through pointer (Segmentation Fault)

I'm writing an application and am having problems with passing a dynamically created array through pointers to the calling function.
I create a pointer in the main to contain the dynamically generated array, and an int to contain the length of that array. I pass those to the readNDEF() function. There it allocates memory based on the read of the needed memory, and reads bytes into the generated array.
Followed a lot of the answers givin here on similar questions but none seem to fix it, of give other errors (eg stack smashing)
int main(void) {
uint8_t *recordPTR; //creating pointer
uint8_t length=0; //creating length variable
readNDEF(recordPTR, &length);
int i;
for (i=0;i<1;i++){
printf("%x ",*(recordPTR+i)); //segmentation fault happens here
}
}
bool readNDEF(uint8_t *messagePTR, uint8_t *messageLength){
int NDEFlength;
if(!(NDEFlength=getNDEFmessageLength())<0){ //get length
closeSession();
return false;
}
uint8_t tempLength=0x00|NDEFlength;
messagePTR = malloc(tempLength*sizeof(uint8_t)+5); //+5 overhead for the rest of the frame
if(messagePTR == NULL){ //check if mallok ok
return false;
}
if(!ReadBinary(0x0002, (uint8_t)0x00|NDEFlength, messagePTR)){ //read NDEF memory
closeSession();
return false;
}
messagePTR++; //skip first byte in the array
closeSession();
*messageLength = tempLength;
//print the array (Works, data correct)
int i;
for (i=0;i<tempLength;i++){
printf("%02x ",*(messagePTR+i));
}
return true;
}
The length returns like it should, but the array itself when enumerating it in the for loop gives a segmentation fault. Using an other way I could enumerate it without the fault, but the data was not correct (random data) probably because it was out of scope after returnign from the function.
Your readNDEF method allocates memory for an object inside that method (because argument of the type pointer, as any other argument in C, is passed by value). Hence the pointer outside has not been changed, and the memory allocated within that function was lost (a memory leak). You need to pass a pointer-to-pointer in order to achieve what you want:
bool readNDEF(uint8_t **messagePTR, uint8_t *messageLength){
///
*messagePTR = malloc(tempLength*sizeof(uint8_t)+5);
}
and call it accordingly:
readNDEF(&recordPTR, &length);

Passing float * and FILE * to/from functions in C

First, I declare variables before the main() function:
// Files
FILE *density_model_file;
char *density_model_filename;
float *density_array;
Next, I open the FILE * for reading and allocate memory for the density array:
density_model_file = open4read(density_model_filename, program_name);
density_array = allocator(density_model_size, sizeof(float));
Up to this point, the debugger shows everything is working fine. Here
is the step that I can't seem to fix, where I am attempting to load
data into the calloc'd array:
density_array = floatfromfile(sizeof(float), density_model_size, density_model_file, density_model_filename);
The density_array has a NULL value after this step for some reason.
Here is the code for this function (contained in a separate .c file).
I have bolded the part where I think the issue exists:
float * floatfromfile(unsigned long int entrysize, int numentries, FILE *inputfile, const char *filename)
{
/* Declaration of density model array size variable */
int numbytes;
**void *temparray = 0;
/* Writes the gravity model to file */
numbytes = (int)fread(temparray, entrysize, numentries, inputfile);**
/* Checks that the forward model file has a sufficient number of entries */
if (numbytes == numentries)
{
printf("loaded %i values from %s using fread()\n", numbytes, filename);
return((float *)temparray);
}
else
{
printf("ERROR: %i data points read from %s of %i needed\n", numbytes, filename, numentries);
return((float *)temparray);
}
}
Any insight would be much appreciated. I think the issue might be that calloc() returns a pointer to a void array. I can provide the other functions if needed.
You seem to have a misunderstanding about how pointers work. What you need to do is pass density_array into floatfromfile as an argument.
What you are doing instead is overwriting the pointer to your allocated memory, with the return value from floatfromfile. That return value is always NULL because that's what you assigned it to (as temparray).
fread expects to be able to write its results into an allocated memory block. But you're giving it temparray which has not been allocated—in fact its value is 0. So you're giving fread the address 0 to write into, which is likely to cause the program to crash. Instead you need to pass your allocated pointer density_array at this point.

Resources