Passing uninitialized 2D arrays as arguments in C - c

all. I've tried and tried to get my head around this, and feel I am almost there, but I'm getting so confused with how many '*' I need! I have a function that takes as input the string of a directory containing a data file, an int and pointers to two uninitialized 2D arrays. The function reads the data file and then allocates memory and fills the arrays accordingly.
This code is completely wrong, I know, but the idea is:
void main()
{
double **Array1;
int **Array2;
int dimension1;
char DirWork[100], buff[100];
f_ReadData(DirWork, dimension1, &Array1, &Array2);
sprintf(buff,"%lf",Array1[0][0]); // Causes segmentation fault
printf(buff);
}
and
void f_ReadData(char *DirWork, int dimension1, double ***Array1ptr, int ***Array2ptr)
{
int ct, ct2;
double **Array1 = *Array1ptr;
int **Array2 = *Array2ptr;
char FullDirArray1[100], FullDirArray2[100];
FILE *d_Array1, *d_Array2;
sprintf(FullDirArray1,"%s%s,DirWork,"Array1.dat");
sprintf(FullDirArray2,"%s%s,DirWork,"Array2.dat");
d_Array1=fopen(FullDirArray1,"r");
d_Array2=fopen(FullDirArray2,"r");
fscanf(d_Array1,"%d", &dimension1);
Array1 = dmatrix(0,dimension1-1,0,3); // allocates memory to Array1 (dimension1 x 3) elements, using nrutil
Array2 = imatrix(0,dimension1-1,0,3); // allocates memory to Array2 (dimension1 x 3) elements, using nrutil
for(ct=0; ct<dimension1; ct++)
{
for(ct2=0; ct2<3; ct2++)
{
fscanf(d_Array1, "%lf", &Array1[ct][ct2];
fscanf(d_Array2, "%d", &Array2[ct][ct2];
}
}
fclose(d_Array1);
fclose(d_Array2);
}
I've missed out error handling here, but I do have some of that in place... not that it's helping. I'm getting a segmentation fault when I try to access the arrays from the main function.
If anyone could help, I'd really appreciate it... I'm seeing *stars! Thank you!

Then number of stars is correct.
You are getting a segfault because you don't copy back the pointer to the buffers that you allocated. You initialize only f_ReadData:Array1 but you need to assign this value back to *Array1ptr.

Related

Why am I getting Segmentation fault for using array of char pointers?

I'm trying to play around with c and pointers since I'm new to the language but I'm not sure why I'm getting a segmentation fault, when I have initialized everything to null then going to re-write the array of char pointers? Can someone explain what I did wrong?
#define MAX_SIZE 70
void gridTest(char*[]);
int main()
{
char *grid[MAX_SIZE] = {0};
testGrid(grid);
return 0;
}
void testGrid(char *grid[]){
for(int i=0;i<MAX_SIZE;i++){
*grid[i] = ' ';
}
for(int j=0;j<MAX_SIZE;j++){
printf("The Character is space, test: %c",*grid[j],j);
}
}
ERROR
Segmentation fault: 11
Check this line
*grid[i] = ' ';
you are trying to store the space character in a memory pointed to by grid[i], that's cool, but where does that one point to?
Answer is: Invalid memory (a null pointer, it is). The memory address you're trying to use is invalid and attempt to deference it invokes undefined behavior.
That being said, seeing your usage, you don't need an array of char pointers, an array of char would suffice. Change your array definition to
char grid[MAX_SIZE] = {0};
and change the called function as
void testGrid(char grid[]){
for(int i=0;i<MAX_SIZE;i++){
grid[i] = ' ';
}
for(int j=0;j<MAX_SIZE;j++){
printf("The Character is space, test: %c",grid[j],j);
}
}
By declaring an array of char pointers, you become responsible for making those pointers point to something. If you just want to get a 70x70 grid, you can get around that by declaring grid as an array of char arrays:
char grid[MAX_SIZE][MAX_SIZE];
That way, the memory is automatically allocated and ready for use.
*grid[i] is equivalent to grid[i][0], so testGrid currently accesses only the first column in each row. To access all cells in the grid, you could use two nested for loops and access them with grid[i][j] or similar.

adding and printing elements of ** pointer that is controlled by a pointer to a struct

I have a struct typedef to SmartArray that has a variable char **array. I have been trying to debug the code for several hours, and have made lots of progress. However, i'm stuck on this particular bug. I have a function to print said array out. It will print twice, and then on the third time it does not print at all! I have a feeling this has something to do with how I am adding malloc to an array being one one does not print out correct. For the last section of the array, it prints "Testing Na". Any ideas? I would appreciate the help.
Here is the part of the function I am suspecting is the cause, however, I can't seem to find it: //allocate min space for string
printf("approaching malloc\n");
strPtr = malloc( sizeof(char) * (strlen(str) + 1) );
if(strPtr == NULL)
{
return NULL;
}
printf("made it past malloc!\n");
strcpy(strPtr, str);
//if crash probably this code
smarty->array[index] = strPtr;
if(smarty->array[0] == NULL)
{
return NULL;
}
return strPtr;
Here is my test code:
typedef struct SmartArray
{
// We will store an array of strings (i.e., an array of char arrays)
char **array;
// Size of array (i.e., number of elements that have been added to the array)
int size;
// Length of the array (i.e., the array's current maximum capacity)
int capacity;
} SmartArray;
int main(void)
{
int i; char buffer[32];
SmartArray *smarty1 = createSmartArray(-1);
printf("Array created\n");
// Print the contents of smarty1.
printf("\n-- SMART ARRAY 1: --\n");
printSmartArray(smarty1);
printf("Made it past print!\n");
put(smarty1,"Hi, my name is ");
put(smarty1, "Hello, my name is");
put(smarty1, "Testing Names");
printf("made it past put!\n");
printf("smart away is now\n");
printSmartArray(smarty1);
printf("end of main!\n");
I feel like it's something completely obvious I'm just overlooking because I am a novice.
Here's a picture of what i'm trying to get it to look like in memory:
click here for memory diagram
UPDATE: I figured out why it wasn't printing all the names, but the program segfaults atfter the print function.
I think it is because you are trying to extend your array using malloc. A C array can only point to one block of storage at a time. When you use malloc it will allocate an entirely new block of storage and you are trying to add that on to the end of your array when you write smarty->array[index] = strPtr.
If you want to extend the size of your C array, use realloc instead which will allocate a new, bigger block of memory for your array and copy the existing content to it as well.
If that doesn't solve the problem can you post your entire put function?

Passing array of pointers to (char) to a function and assigning a string to each

What i´m trying to do is assigning strings to pointers in a vector from a separate function for that use. unfortunately i keep getting either a lot of warnings or errors or bus trap:10.
here´s the code so far here i commented where i´m having issues:
#include <stdio.h>
#include <stdlib.h>
void read_top(FILE **read,short int *L, short int *D, short int *N){
fscanf(*read,"%hd %hd %hd",L,D,N); // L being the size of the strings, D being how many strings there are and N doesn´t matter for this question
fgetc(*read); // remove \n
}
void save_words(FILE **read,char **dic,short int L,short int D){ // i´m having problems here assigning strings to the pointers
int e;
for (e = 0;e < D;e++){
*dic[e] = malloc(125);
fgets(*dic[e],L+1,*read);
fgetc(*read);
}
}
void open(FILE **read,FILE **write) {
*read = fopen("teste4.in","r");
*write = fopen("Allien_language","w");
}
void alloc(char **dic,D,L){ //i´m having problems here allocating memory for each pointer to point to
int e;
for (e = 0;e < D; e++){
*dic[e] = malloc(L);
}
}
main(){
FILE *read,*write;
open(&read,&write);
short int L,D,N;
read_top(&read,&L,&D,&N);
char *dic[D]; // here´s the array of pointers
alloc(dic,D,L); // here´s the funtion i can´t get to work
save_words(&read,dic,L,D); // here´s the function that i can´t get to work
//printf("\n%s\n",dic[0]);
}
I´ve tried multiple things, but i think the main problem is not knowing exactly how things work. this includes passing the array to the function and assigning the strings to it and allocating the memory for each pointer. I´ve also been searching in this site for my questions, where i found solutions to similar problems but didn´t understand exactly their solutions. If someone could explain me exactly how things should work i would appreciate that.
thanks in advance
When you do e.g. *dic[e] = malloc(...) you're doing it wrong. What the expression *dic[e] does is get element e of the array dic, which is a pointer to char, then you dereference the pointer giving you the value of what dic[e] is pointing to. Unfortunately dic[e] doesn't point anywhere yet, which would lead to undefined behavior and a probable crash if the compiler didn't give you an error.
And you get an error because you try to assign the pointer returned by malloc to something that's not a pointer.
So the solution? Remove the dereference, and just do e.g. dic[e] = malloc(...).
You have the same problem when you try to read the string from the file in save_words. And there you have another problem, you allocate memory for the string again, making you loose the original allocation from the alloc function, and leading to a memory leak.
The problem is that you are treating elements of the array of pointers incorrectly: rather than assigning
*dic[e] = malloc(L);
you should be assigning
dic[e] = malloc(L);
without the dereference operator.
The reason for this is that you are passing an array of uninitialized pointers, so you may not dereference them. However, you can certainly assign them, which is what dic[e] = malloc(L) does.
You have the same problem in save_words. The fix is even simpler there - you need to drop the *dic[e] = malloc(125); line, because it re-assigns a pointer that has been assigned already.
Finally, you need to remove dereference operator from this line as well:
fgets(dic[e],L+1,*read); // No asterisk in front of "dic[e]"

Why will this not print?

Before you feel the need to mark this as a duplicate post, please don't. I have read all the threads on pointers, arrays, and functions I could find but almost all of them are far too advanced to be of any help to me.
I'm not getting an error, however my code will not print my array. It seems the issue here is using scanf. I don't think the values entered are actually being put into the array in main(). I've tried using pointers, but then I get the error "Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)" whenever I try to use scanf to collect user inputted values to put into the array.
What I am working on is limited to declaring my array in the main() function, but all the operations are to be performed in promptData() function. Any help would be great, I'm at my wits end trying to figure this out on my own.
#import <stdio.h>
void promptData(double data[], int numElem);
int main(int argc, const char * argv[])
{
int size, i;
double array[size];
promptData(array, size);
for (i = 0; i < size; i++)
printf("%.2lf\n", array[i]);
return 0;
}
void promptData(double data[], int numElem)
{
int i;
printf("Enter integer values for size of array.\n");
scanf("%i", &numElem);
for (i = 0; i < numElem; i++)
{
printf("Enter array values.\n");
scanf("%lf", &data[i]);
}
}
Your program has undefined behaviour because variable size was not initialized and has indeterminate value.
You should at first in main ask the user to enter the size of the array then define the array itself and only after that fill it with values.
For example
int main(int argc, const char * argv[])
{
int size = 0;
printf( "Enter a positive integer value for the size of the array: ");
scanf( "%i", &size);
if ( size == 0 ) exit( 1 );
double array[size];
promptData(array, size);
//...
Also in C there is no such a directive as
#import <stdio.h>
Use instead
#include <stdio.h>
At least in ANSI C 89 and C 90, you can't give a variable as the size of an array. The size of array should be known at compile time. You should be doing something like double array[size];.
Even in C99, where you can have variable sized arrays; the variables should contain proper index values at the time you declare the array. In that case, you should read the number from stdin and then declare the array.
Also in C, all parameters are passed by value. This means every function takes a copy of the parameters in the function. If you want to modify a variable's value, you should pass a pointer to it, and then modify the pointer's dereferenced value, something like:
void change(int *x)
{
*x = 7;
}
void first(void)
{
int x = 5;
change(&x);
printf("%d\n", x);
}
Adding on to the other, correct, answer by Zenith, if you want a dynamically allocated array (like you want to be able to change its size based on user input), then your only option is to use one of the memory allocation functions like malloc().
Once you actually have the size in your main function, declare your array like this:
int *myArray = malloc(sizeof(int) * size));//note that malloc will return a NULL if it fails
//you should always check
if(myArray != null) {
//do stuff with myArray like you were. You can just use myArray[] as long as you
//make SURE that you don't go beyond 'size'
}
free(myArray);
//VERY important that every malloc() has a free() with it
Note: untested, but the idea is there.
Further, to answer your other question.
If you find yourself in a situation where you need to call a function and use things INSIDE that function to change stuff where you called it, you have only two choices in C.
You can either return the value and assign it to a variable in the calling function like this:
int result = myFunction(someVariable, anotherVariable);
//do stuff with result
Or, use pointers.
I'm not explaining pointers here, that's usually several lectures worth of information, and is one of the more difficult concepts to grasp for introductory programmers. All I can tell you is you need to learn them, but this format is not the right way to go about doing that.
You're passing size to promptData as a copy.
Thus changes to numElem inside promptData will not affect the size variable in your main. Hence size remains uninitialized, i.e. has an undefined value and therefore should not be used as a size for an array.
If you need to initialize an array with a size that's only known at run-time, you need to allocate memory for the array dynamically using malloc, for example:
double* array = malloc(size * sizeof(double));

Crash while re-organizing 1d buffer as 2d array

I have a 1d buffer which i have to re-organize to be accessed as a 2d array. I have pasted my code below:
#include <stdlib.h>
#include <stdio.h>
void alloc(int ** buf, int r, int c)
{
int **temp=buf;
for(int i=0; i<r; i++)
buf[i]=(int *)temp+i*c;
}
void main()
{
int *buffer=(int *)malloc(sizeof(int)*100);
int **p = (int**) buffer;
alloc(p, 4, 4);
//for(int i=0;i<r;i++)
//for(int j=0;j<c;j++)
// printf("\n %p",&p[i][j]);
p[0][3]=10;
p[2][3]=10;
p[3][2]=10; //fails here
printf("\n %d", p[2][3]);
}
The code is crashing when i make the assignment.
I have ran the code for different test cases. I have observed that the code crashes when there is an assignment to p[0][x] followed by assignment to p[x][anything] with the code crashing at the second assignment. This crash is seen only when the first index of the first assignment is 0 and for no other indices with the crash happening at the second assignment having the first index equal to the second index of the first assignment.
For example, in the above code crash happens at p[3][2] after p[0][3] has been executed. If i change the first assignment to p[0][2] then crash would happen at p[2][3]( or p[2][anything] for that matter).
I have checked the memory pointed to by p, by uncommenting the double for loop, and it seems to be fine. I was suspecting writing at illegal memory locations but that has been ruled out by the above observation.
The problem is that your 2D array is actually an array of pointers to arrays. That means you need to have space for the pointers. At the moment you have your pointers in positions 0-3 in the array, but p[0] is also pointing to position 0. When you write to 'p[0,3]' you are overwriting p[3].
One (tempting) way to fix it is to allow the pointers room at the start of the array. So you could change your alloc method to allow for some space at the front. Something like:
buf[i] = (int *)(temp+r) + i*c;
Note the +r adding to the temp. It needs to be added to temp before it is cast as you can't assume int and int * are the same type.
I would not recommend this method as you still have to remember to allocate extra space in your original malloc to account for the array of pointers. It also means you aren't just converting a 1D array to a 2D array.
Another option would be to allocate your array as an array of pointers to individually allocated arrays. This is the normal way to allocate 2D arrays. However this will not result in a contiguous array of data as you have in your 1D array.
Half way between these two options, you could allocate an extra array of pointers to hold the pointers you need, and then point them to the data. Change your alloc to something like:
int **alloc(int * buf, int r, int c)
{
int **temp = (int **)malloc(sizeof (int *)* r);
for (int i = 0; i<r; i++)
temp[i] = buf + i*c;
return temp;
}
then you call it like:
int **p = alloc(buffer, 4, 4);
you also need to free up the extra buffer.
This way your data and the pointers you need to access it are kept separate and you can keep your original 1D data contiguous.
Note that you don't need to cast the result of malloc in c, in fact some say that you shouldn't.
Also note that this method removes all of the requirement for casting pointers, anything that removes the need for a cast is a good thing.
I think that your fundamental problem is a misconception about 2D arrays in C (Your code is C, not C++).
A 2D array is a consecutive memory space , and the size of the inner array must be known in advance. So you basically cannot convert a 1D array into a 2D array unless the size of the inner array is known at compile time. If it is known, you can do something like
int *buffer=(int *)malloc(sizeof(int)*100);
typedef int FourInts[4];
FourInts *p = (FourInts *)buffer;
And you don't need an alloc function, the data is already aligned correctly.
If you don't know the size of the inner array in advance, you can define and allocate an array of arrays, pointing into the 1D buffer. Code for that:
int ** alloc(int * buf, int r, int c)
{
int **array2d = (int **) malloc(r*sizeof(int *));
for(int i=0; i<r; i++)
array2d[i] = buf+i*c;
return array2d;
}
void _tmain()
{
int *buffer=(int *)malloc(sizeof(int)*100);
int **p = alloc(buffer,4,4);
p[0][3]=10;
p[2][3]=10;
p[3][2]=10; //fails here
printf("\n %d", p[2][3]);
free(buffer);
free(p);
}
But it would have been easier to simply build an array of arrays without using the buffer. If you could use C++ instead of C, then everything could be easier.
If you already have a 1D block of data, the way to make it accessible as a 2D array is to create an array of pointers - one for each row. You point the first one to the start of the block, the next one is offset by the number of columns, etc.
int **b;
b = malloc(numrows*sizeof(int*));
b[0]=temp; // assuming temp is 1D block
for(int ii=1; ii<numrows;ii++)
b[ii]=b[0]+ii*numcols;
Now you can access b[i][j] and it will point to your original data. As long as number of rows and columns are known at run time this allows you to pass variable length 2D arrays around. Remember that you have to free the vector of pointers as well as the main data block when you are done or you will get a memory leak.
You will find examples of this if you google nrutil.c - this is derived from the trick Numerical Recipes in C uses.
This function prototype should be:
void alloc(int *buf[][], int r, int c) //buf[][] <=> **buf, but clearer in this case
{
//*(buf[i]) =
...
}
If you want to work on the same array you have to pass a pointer to this 2D array (*[][]).
The way you do it now is just working on a copy, so when you return it's not modified.
You should also initialize your array correctly :
p = malloc(sizeof(int *[]) * nb of row);
for each row
p[row] = malloc(sizeof(int []) * nb of col);

Resources