multidimensional array: incompatible type assignment - c

I have declared array of known size,
typedef struct{
......
char * buffer[height+1]; //height is a constant int
......} args;
int main{
args * info;
info = malloc (sizeof(args));
char* output_buffer[width][height+1]; //width is also a constant int >= 4
output_buffer[2] = malloc (sizeof(char)*char_per_line*(height+1)); // error same as below
info->buffer = output_buffer[2]; // I know it's wrong. incompatible types in assignment
....}
Numbers are arbitrary and used just for illustration.
What i am doing is to assign the address of output_buffer[width] to info->buffer, and then pass info as an argument to a thread, which generates data an array of size height+1; in each slot is a cstring of length char_per_line. Those cstrings are stored in output_buffer[2].
I am confused here that isn't the output_buffer[2] a pointer of type char*[height+1]? Then why can't I assign address of memory from malloc to it?
Also, I know that I cannot assign an array to an array, but how can I get the code work in desired way? If the solution is to use a char** as char*[height+1], then how can I access info->buffer[height], say?
Thanks in advance!

According to the requirement you are specifying, this is what you need to do
/* This is a 2D array of pointers. */
char* output_buffer[width][height+1];
for ( int i =0; i< width; i++ )
for ( int j=0; j <height+1; j++ )
output_buffer[i][j] = malloc (sizeof(char)*char_per_line*(height+1));
And then,
info->buffer[SOME_VALUE] = output_buffer[SOME_WIDTH][SOME_HEIGHT];
I am confused here that isn't the output_buffer[2] a pointer of type
char*[height+1]? Then why can't I assign address of memory from malloc
to it?
malloc returns a single dimensional pointer void* but as you have noted, output_buffer[2] is not a single dimensional pointer. It is of type char*[height+1]. [] adds one more dimension apart from the *.

isn't the output_buffer[2] a pointer of type char*[height+1]?
No. output_buffer[2] is an array of size height+1. Its element type is char*.
Then why can't I assign address of memory from malloc to it?
As you know, you cannot assign to an array.
array of size height+1; in each slot is a cstring of length char_per_line.
how can I get the code work in desired way?
If you need an array of (height+1) C strings, each of size char_per_line, you need to allocate (height+1) C strings of size char_per_line. That is, call malloc (height+1) times and pass char_per_line to each. (There's a way to do it in one call to malloc but you probably don't want to do that right now).

typedef struct{
......
char * buffer[height+1]; //height is a constant int
......} args
this has to be
typedef struct{
......
char ** buffer; //height is a constant int
......} args
output_buffer[2] = malloc (sizeof(char)*char_per_line*(height+1));
you have to this in a for loop, and for all output_buffer[i][j], (now it is char ** = char *).

Related

access to a member of a struct (pointer) with the use of double pointer

hey I am trying to create a program in which I am trying store elements from one array to another with the use of a pointer to pointer but the problem is that is caused undefined behavior I believe that the problem is that I do not pass the elements in members with a proper way
I know it is a vague way of doing this but It is in only for practising reasons
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct student{
char *name;
int *number;
}T;
int main(void) {
char array[10][100]={"araaaa","bbgt","gffkghgh"};
T arr[10][100];
T *p;
T **p1;
p=&arr[0][0];
p1=&p;
int i=0;
for(i = 0 ; i < 3 ; i++)
{ p=arr[i];
strcpy((*p1)->name,array[i]);
}
/*******print_elements*************/
for(i = 0 ; i < 3 ; i++)
{ p=arr[i];
printf("\n the elements are %s",(*p1)-> name);
}
return 0;
}
When you do this:
strcpy ((*p1)->name, array[i]);
(*p1)->name is an uninitialised pointer. What happens, therefore, is in the lap of the gods.
The easiest fix is to modify your student structure such that name is a buffer, rather than a pointer. At the same time, change number to an int, rather than a pointer to an int::
typedef struct student{
char name [100];
int number;
} T;
If you want to keep name as a pointer then you have to allocate some memory before you store your string in it. This should work:
(*p1)->name = strdup (array[i]);
Don't forget to free the memory when done.
T is made of of two pointers, this first one points to a string of characters in memory.
arr is a 2D array that is allocated to store a total of 1000 T structures.
arr[i] would reference a 1D array of T structures within arr
*p1 would essentially be arr[i], since dereferencing p1 gives you p, which was just set to arr[i]. So, that is not a pointer to a T structure, but to an array of T structures. Forcing the cast will likely give you a reference to the first T structure in that row, however.
->name This value is never set. You allocated an array, but "name" is a pointer to memory, not an array of characters, so '->name' is undefined.
I think you need to change arr to be a single dimension array. You aren't using 90% of it.
And, you need to initialize every T struct in that array. You can use malloc or strdup, and then remember to free them all. Or, set the struct to use an array instead.

How to use double pointer as pointer arrays?

Version 1:
struct mydef_s1 {
int argc;
char *argv[3];
};
struct mydef_s1 *p1 = (struct mydef_s1*) malloc (sizeof (struct mydef_s1));
p1->argv[0] = malloc (8);
p1->argv[1] = malloc (16);
p1->argv[2] = malloc (24);
Now, I want to achieve above with the following structure declaration?
Version 2:
struct mydef_s2 {
int argc;
char **argv;
};
If I am right, then following would like allocate just 8 bytes (4 for memory pointer & 4 for integer in my machine)
struct mydef_s2 *p2 = (struct mydef_s2*) malloc (sizeof (struct mydef_s2));
What should I do to do the following?
p2->argv[0]= malloc(4);
p2->argv[1]=malloc(8);
In the case of a pointer to pointer like
struct mydef_s2 {
int argc;
char **argv;
};
you have to first allocate the memory for argv itself, then for argv[i]s.
Something like (code is without error check)
argv = malloc(n * sizeof*argv); //allocate memory to hold 'n' number of 'argv[i]'s
for (i = 0; i < n; i++)
argv[i] = malloc(32); //allocate individual `argv[i]`s
will do the job.
A pointer in C is behaving somewhat like an array. A pointer to pointer, however, is something completely different than a two dimensional array.
If you meant what you typed, i.e. - an array of a non (compiled time) known size of pointers to arrays of non compiled time known sizes of chars, then you will need to do just that. Allocate storage for the array of pointers, place that in your argv, and then initialize each position there with a pointer, possibly dynamically allocated with malloc, of the actual array of chars.
If, on the other hand, you meant a two dimensional array, you have two ways to proceed. One is to do the above, possibly saving a step by allocating the inner nesting in one malloc at one go. This is somewhat wasteful in memory.
The other option is to simulate what the compiler does for two dimensional arrays. Allocate n*m chars as a single dimension array, and jump into it by with the formula i = r*m + c, where r is the row index, m is the row size, and c is the column index.
While somewhat verbose, this is what C does when you define a two dimensional array. It is also quicker to allocate, initialize and use than the alternative.

Handling an array of pointers

I'm attempting to create a struct that has an array of char pointers as one of its members and am having trouble attempting to set/access elements of the array. Each char pointer is going to point to a malloc'd buffer. This is the struct currently.
struct rt_args {
long threadId;
char (*buffers)[];
FILE* threadFP;
};
And when I attempt to access an element of buffers via
char *buffer = malloc(100);
struct rt_args (*rThreadArgs) = malloc( sizeof(long) +
(sizeof(char *) * (numThreads)) +
sizeof(FILE*)
);
rThreadArgs->buffers[0] = buffer;
I get the error "invalid use of array with unspecified bounds". I don't know what the size of the array is going to be beforehand, so I can't hardcode its size. (I've tried de-referencing buffers[0] and and adding a second index? I feel as though its a syntactical error I'm making)
You can't have arrays without a size, just like the error message says, at least not n the middle of structures. In your case you might think about pointers to pointers to char? Then you can use e.g. malloc for the initial array and realloc when needed.
Something like
char **buffers;
Then do
buffers = malloc(sizeof(buffers[0]) * number_of_pointers_needed);
Then you can use buffers like a "normal" array of pointers:
buffers[0] = malloc(length_of_string + 1);
strcpy(buffers[0], some_string);
char (*buffers)[SIZE];
declares buffers as a pointer to char array not the array of pointers. I think you need this
char *buffers[SIZE];
NOTE: Flexible array member can be used only when it is the last member of the structure.

Declare and allocate memory for an array of structures in C

I'm trying to declare and allocate memory for an array of structures defined as follows:
typedef struct y{
int count;
char *word;
} hstruct
What I have right now is:
hstruct *final_list;
final_list = calloc (MAX_STR, sizeof(hstruct));
MAX_STRbeing the max size of the char word selector.
I plan on being able to refer to the it as:
final_list[i].count, which would be an integer and
final_list[i].word, which would be a string.
ibeing an integer variable.
However, such expressions always return (null). I know I'm doing something wrong, but I don't know what. Any help would be appreciated. Thanks.
A struct that contains a pointer doesn't directly holds the data, but holds a pointer to the data. The memory for the pointer itself is correctly allocated through your calloc but it is just an address.
This means that is your duty to allocate it:
hstruct *final_list;
final_list = calloc(LIST_LENGTH, sizeof(hstruct));
for (int i = 0; i < LIST_LENGTH; ++i)
final_list[i].word = calloc(MAX_STR, sizeof(char));
This requires also to free the memory pointed by final_list[i].word before releasing the array of struct itself.

passing element of dynamic multidimensional array to a function

I have code which already works but am trying to extend it.
unsigned char **data_ptr;
Allocate memory for the first "array"
data_ptr = (unsigned char **)malloc(sizeof(unsigned char **) * no_of_rows);
Then in a loop initialize each row
data_ptr[index] = (unsigned char *)malloc(sizeof(unsigned char*), rowsize));
I then pass the address of my array to a library function. It works fine if I just pass the start of a row...
LibFunction( info_ptr, &data_ptr[index] ) //OK
But I need to pass the address of where in a row I want the function to begin writing data.
These both compile but fail in operation
LibFunction( info_ptr,(unsigned char **)data_ptr[index] + 1);
or..
LibFunction( info_ptr,(unsigned char **)data_ptr[index][1]);
LibFunction is of the form
LibFunction(..., unsigned char **)
I'm allocating more memory than I need with rowsize so I don't think I'm overrunning the array. As I stated, the code works fine if I pass it the start of a row but bugs out if I
try to pass any other element. There may be something else wrong but I need to know first if my syntax is ok.
Can't find anything else on the net as regards passing the address of single element of dynamic 2d array.
LibFunction( info_ptr,(unsigned char **)data_ptr[index] + 1);
is wrong because data_ptr is an unsigned char **, so data_ptr[index] is an unsigned char *. Leave out the cast and correct the function you're calling, it should accept an unsigned char *.
Some corrections in your program, observed from the top few lines
Since,
unsigned char **data_ptr; // a pointer to a char pointer
get the sizeof(char*) and always avoid typecasting the pointer returned by malloc()
data_ptr = malloc(sizeof(unsigned char *) * no_of_rows);
And for doing the allocation for the rows,
data_ptr[index] = (unsigned char *)malloc(sizeof(unsigned char*)* rowsize));
To pass the address of where in a row you want the function to begin writing data, change the function signature as
LibFunction(..., unsigned char *)
It should be LibFunction(&data_ptr[row][start_here]), exactly the same as if it was just an unsigned char[ROWS][COLUMNS];.
In general, it is my experience that if you think you require casts in modern-day C, it is probable that you are muddled up with what you are trying to do. A nice read is a comment on a post by Linus Torvalds on /. on this kind of stuff.
You're not allocating room for no_of_rows pointers to pointers; there's an asterisk too many in there. Also, you really [shouldn't cast the return value of malloc(), in C][1].
Your first allocation should be:
data_ptr = malloc(no_of_rows * sizeof *data_ptr);
But I need to pass the address of where in a row I want the function to begin writing data
So let's start simple, to make an array the correct size, forget trying to get the sizeof a complex type, we can simply do this:
unsigned char **data_ptr;
data_ptr = malloc(sizeof(data_ptr) * no_of_rows); //Just sizeof your var
Now you've got the correct memory malloc'd next you can malloc the memory for the rest easily:
for(index = 0; index < no_of_rows; index++)
data_ptr[index] = malloc(sizeof(unsigned char*) * rowsize);
Last point, now that we've got all that set up, you should initialize your array:
for(index = 0; index < no_of_rows; index++)
for(index2 = 0; index2 < rowsize; index2++)
data_ptr[index][index2] = 0;
As for your function, you want it to take a "portion" of an array, so we need it to take an array and a size (the length of the array to initialize):
void LibFunction(unsigned char data[], int size);
Then we're your ready to store some data it's as easy as:
LibFunction(&data_ptr[1][2], 3); // store data in second row, 3rd column, store
// three values.
You can do something like this:
unsigned char* ptr = &data[0][1];
LibFunction(info_ptr, &ptr);

Resources