How to initialize and save data to 2d array in C - c

If I had a 2d array with multiple c strings, how would I initialize the array without knowing how many c string will be added into that array.
I have tried to initialize like below but when I try to add a c string I get an error when compiling.
Error : explicit dimensions specification or initializer for an auto or static array.
static Char data[][100];
int main(){
int i;
char word[5];
strcpy(word,"data");
For(i=0; i < rows; i++){
strcpy(data[i],word);
}
}
So the array should hold for example
data[][100]= {"data","data"};
The row value depends on how many rows are retrieved from an sql so my problem is I want to somehow dynamically create the array to fit the size of the rows retrieved from the SQL.
Any help or information would be great.

You can use a pointer to array and reallocation.
#include <stdlib.h> /* for realloc() */
#include <string.h> /* for strcpy() */
int rows = 100; /* for example */
static char (*data)[100] = NULL;
int main(){
int i;
char word[100]; /* allocate array, not a single char */
strcpy(word,"data");
for(i=0; i < rows; i++){
char (*newData)[100] = realloc(data, sizeof(*data) * (i + 1));
if (newData == NULL) { /* allocation error */
free(data);
return 1;
}
data = newData;
strcpy(data[i],word);
}
}

If you don't know how many strings there will be in advance, you either have to set a fixed maximum limit to the static array, or alternatively use dynamic allocation of an array of char pointers.
When using dynamic allocation, you can malloc a "pretty large number" at first, keep track of how many strings there are, and then realloc when you run out of space.
EDIT: pseudo-code example without error handling, free() etc
int main (void)
{
size_t alloc_size = sizeof(char*[100]);
char** data = malloc(alloc_size);
for(size_t i=0; i<rows; i++){
if(i > alloc_size)
{
alloc_size *= 2;
data = realloc(data, alloc_size);
}
size_t str_size = strlen(input)+1;
data[i] = malloc(str_size);
memcpy(data[i], input, str_size);
}
}

Related

Memory allocation error (I think?) in a dynamically sized shopping list.

I've included the code below if anyone would be kind enough to complile it to really see the problem. I'm trying to make a dynamically allocated shopping list to get my used to pointers and memory allocation.
The entries is stored in a 1D char array (seperated by null pointers). Arrays containing the location of the first character and entry length have also been created in order to navigate the list.
The code works for small entries, but when I use a list of large entries (e.g. 'adsjasdkasjdaksdj') suddenly my code thinks the length (strlen(message)) is something like '110040'. To me this looks like a memory error but I'm no computer scientist (more of an amateur coder). I tried extending the memory allocated using realloc() but the problem persists.. Any help would be greatly appreciated!
I've put the code in a loop to take 10 entries for testing purposes.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int listEntries = 0;
int main(int argc, const char * argv[]) {
//Initial definition and allocation of memory.
char *list;
list = (char *)malloc(sizeof(char)); //allocates the requested memory and returns a pointer to it.
int *entryLength; //Array to hold length of each entry.
entryLength = (int *)malloc(sizeof(int)); //allocates the requested memory and returns a pointer to it.
int *entryStart; //Array to hold start point of each entry.
entryStart = (int *)malloc(sizeof(int)); //allocates the requested memory and returns a pointer to it.
char *message; //Array to hold the user input.
message = (char *)malloc(sizeof(char)); //allocates the requested memory and returns a pointer to it.
int arraySize = 0; //Variable to hold the size of the array.
char input[32]; //Char array to take user input (copied to 'message' later)
for(int i=0;i<10;i++){
//Obtain user entry.
printf("Insert entry: \n");
scanf("%s",input);
//Transfer string pointer contents to usable char array of known size.
message = (char *)realloc(message, strlen(input)*sizeof(char));
int i=0;
while(input[i] != '\0'){
message[i] = input[i];
i++;
}
message[i]='\0';
//Add entry to list.
listEntries++;
//Find the current size of list.
arraySize=0;
for(i=0;i<listEntries;i++) {
arraySize+=entryLength[i];
printf("entryLength[%d] = %d\n",i,entryLength[i]);
}
//Reallocate memory to accomodate new data.
list = (char *)realloc(list, (arraySize+1)*sizeof(char)+2);
entryLength = (int *)realloc(entryLength,(listEntries*4)*sizeof(int)+2); //Over allocating
entryStart = (int *)realloc(entryStart,(listEntries*4)*sizeof(int)+2); //For safety in dev.
//Add new entry to data.
entryLength[listEntries-1]=(int)strlen(message);
printf("entryLength[%d] is: %d",listEntries-1,entryLength[listEntries-1]);
entryStart[listEntries-1]=arraySize;
//printf("Start point is: %d",entryStart[listEntries-1]);
for(i = 0; i < strlen(message); i++){
list[i+arraySize] = message[i];
}
//Print the new entry
for(int i = 0; i < arraySize; i++){
printf("%c",list[i]);
}
printf("\n");
}
}

Dynamically allocating 2-dimensional array in Struct (in C)

I have a structure called container that has two fields: labels and linked_to_containers; The field labels is designed to be a 2-dimensional array of int, and the field linked_to_containers is designed to be a 2-dimensional array of int pointers. On top of this, I also have an array of struct container that are dynamically created in the initiation program. I have the following code written down, but one thing I'm unsure about is the first malloc I used inside of the function container_init(). As the struct container still does not have its size initialized, is this the right way to do malloc for creating an array of struct container?
Please see my question in my comments in the code, and I will appreciate your feedback.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct container {
int *labels[2]; /* two-dimensional array of int */
int **linked_to_container[2]; /* two-dimensional array of pointers to label */
} container;
int get_next_container_index(int current_container_index, int max_index)
{
if (max_index - current_container_index >= 1)
{
return current_container_index + 1;
}
else
return 0; /* elements at two ends are linked */
}
container *allcontainers; /* an array for all containers */
void container_init(int num_containers, int column_num)
{
/* is this right to malloc memory on the array of container when the struct size is still unknown?*/
allcontainers = (container *) malloc(num_containers * sizeof(container));
int i;
for (i = 0; i < num_containers; i++)
{
container *current_container = &allcontainers[i];
current_container->labels[0] = malloc(column_num * sizeof(int));
current_container->labels[1] = malloc(column_num * sizeof(int));
current_container->linked_to_container[0] = malloc(column_num * sizeof(int *));
current_container->linked_to_container[1] = malloc(column_num * sizeof(int *));
int j;
for (j = 0; j < column_num; j++)
{
current_container->labels[0][j] = 0; /* initialize all labels to 0 */
current_container->labels[1][j] = 0;
int next_container = get_next_container_index(i, num_containers - 1); /* max index in all_containers[] is num_containers-1 */
current_container->linked_to_container[0][j] = &(allcontainers[next_container]->labels[0]);
}
}
The line in question seems perfectly fine to me, the size of struct container is well-known, because of its definition. The only size not known is the size of the arrays that the pointers in the struct will eventually point to, but that doesn't affect the size of the pointers themselves and thus also not the struct's size.
The only issue I see is here:
current_container->linked_to_container[0][j] = &(allcontainers[next_container]->labels[0]);
linked_to_container[0][j] is of type int*, but labels[0] is of type int* and therefore &(labels[0]) is of type int**. I am not sure what you try to accomplish here, but you probably need another index to labels[0][...] or & shouldn't be there.

Copying Array of Char * Corrupts Data

I'm relatively new to C in general and I'm having a problem with some code. It's pretty simple code: The objective of the code is to copy a given array of char pointers, or char **source, in other words, to a given char **destination.
The issue I'm having is that sometimes (usually when I have more than 2 strings in source) the first element gets completely corrupted and when I end up printing out destination, it will print out something like ";#?" for the first element, with the other elements printing fine.
The code that performs the copying is:
void CopyArrayOfStrings(char **source, int numStrings)
{
char **destination = malloc(numStrings);
for (int i = 0; i < numStrings; i++)
{
destination[i] = malloc(strlen(source[i] + 1);
strcpy(destination[i], source[i]);
}
}
Note that I left out the code that checks if the result of malloc is NULL.
You need to change your allocation of destination as :
char **destination = malloc(numStrings*(sizeof(char*)));
to allocate number of char * pointers to hold strings.
Also verify you are appropriately passing char ** as source array of strings.
You're doing it wrong.
void CopyArrayOfStrings(char **source, int numStrings)
{
char **destination = malloc(numStrings * sizeof(char *));
for (int i = 0; i < numStrings; i++)
{
destination[i] = malloc(strlen(source[i]) + 1);
strcpy(destination[i], source[i]);
//alternatively you can use strdup() as suggested by #Christoffer
}
}
This will give you storage space for numStrings arrays. Each element of which, will point to a null-terminated string.

C Dynamically creating array of structs which include variable sized 2d array [duplicate]

I know how to create an array of structs but with a predefined size. However is there a way to create a dynamic array of structs such that the array could get bigger?
For example:
typedef struct
{
char *str;
} words;
main()
{
words x[100]; // I do not want to use this, I want to dynamic increase the size of the array as data comes in.
}
Is this possible?
I've researched this: words* array = (words*)malloc(sizeof(words) * 100);
I want to get rid of the 100 and store the data as it comes in. Thus if 76 fields of data comes in, I want to store 76 and not 100. I'm assuming that I don't know how much data is coming into my program. In the struct I defined above I could create the first "index" as:
words* array = (words*)malloc(sizeof(words));
However I want to dynamically add elements to the array after. I hope I described the problem area clearly enough. The major challenge is to dynamically add a second field, at least that is the challenge for the moment.
I've made a little progress however:
typedef struct {
char *str;
} words;
// Allocate first string.
words x = (words) malloc(sizeof(words));
x[0].str = "john";
// Allocate second string.
x=(words*) realloc(x, sizeof(words));
x[1].FirstName = "bob";
// printf second string.
printf("%s", x[1].str); --> This is working, it's printing out bob.
free(x); // Free up memory.
printf("%s", x[1].str); --> Not working since its still printing out BOB even though I freed up memory. What is wrong?
I did some error checking and this is what I found. If after I free up memory for x I add the following:
x=NULL;
then if I try to print x I get an error which is what I want. So is it that the free function is not working, at least on my compiler? I'm using DevC??
Thanks, I understand now due to:
FirstName is a pointer to an array of char which is not being allocated by the malloc, only the pointer is being allocated and after you call free, it doesn't erase the memory, it just marks it as available on the heap to be over written later. – MattSmith
Update
I'm trying to modularize and put the creation of my array of structs in a function but nothing seems to work. I'm trying something very simple and I don't know what else to do. It's along the same lines as before, just another function, loaddata that is loading the data and outside the method I need to do some printing. How can I make it work? My code is as follows:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
typedef struct
{
char *str1;
char *str2;
} words;
void LoadData(words *, int *);
main()
{
words *x;
int num;
LoadData(&x, &num);
printf("%s %s", x[0].str1, x[0].str2);
printf("%s %s", x[1].str1, x[1].str2);
getch();
}//
void LoadData(words *x, int * num)
{
x = (words*) malloc(sizeof(words));
x[0].str1 = "johnnie\0";
x[0].str2 = "krapson\0";
x = (words*) realloc(x, sizeof(words)*2);
x[1].str1 = "bob\0";
x[1].str2 = "marley\0";
*num=*num+1;
}//
This simple test code is crashing and I have no idea why. Where is the bug?
You've tagged this as C++ as well as C.
If you're using C++ things are a lot easier. The standard template library has a template called vector which allows you to dynamically build up a list of objects.
#include <stdio.h>
#include <vector>
typedef std::vector<char*> words;
int main(int argc, char** argv) {
words myWords;
myWords.push_back("Hello");
myWords.push_back("World");
words::iterator iter;
for (iter = myWords.begin(); iter != myWords.end(); ++iter) {
printf("%s ", *iter);
}
return 0;
}
If you're using C things are a lot harder, yes malloc, realloc and free are the tools to help you. You might want to consider using a linked list data structure instead. These are generally easier to grow but don't facilitate random access as easily.
#include <stdio.h>
#include <stdlib.h>
typedef struct s_words {
char* str;
struct s_words* next;
} words;
words* create_words(char* word) {
words* newWords = malloc(sizeof(words));
if (NULL != newWords){
newWords->str = word;
newWords->next = NULL;
}
return newWords;
}
void delete_words(words* oldWords) {
if (NULL != oldWords->next) {
delete_words(oldWords->next);
}
free(oldWords);
}
words* add_word(words* wordList, char* word) {
words* newWords = create_words(word);
if (NULL != newWords) {
newWords->next = wordList;
}
return newWords;
}
int main(int argc, char** argv) {
words* myWords = create_words("Hello");
myWords = add_word(myWords, "World");
words* iter;
for (iter = myWords; NULL != iter; iter = iter->next) {
printf("%s ", iter->str);
}
delete_words(myWords);
return 0;
}
Yikes, sorry for the worlds longest answer. So WRT to the "don't want to use a linked list comment":
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char** words;
size_t nWords;
size_t size;
size_t block_size;
} word_list;
word_list* create_word_list(size_t block_size) {
word_list* pWordList = malloc(sizeof(word_list));
if (NULL != pWordList) {
pWordList->nWords = 0;
pWordList->size = block_size;
pWordList->block_size = block_size;
pWordList->words = malloc(sizeof(char*)*block_size);
if (NULL == pWordList->words) {
free(pWordList);
return NULL;
}
}
return pWordList;
}
void delete_word_list(word_list* pWordList) {
free(pWordList->words);
free(pWordList);
}
int add_word_to_word_list(word_list* pWordList, char* word) {
size_t nWords = pWordList->nWords;
if (nWords >= pWordList->size) {
size_t newSize = pWordList->size + pWordList->block_size;
void* newWords = realloc(pWordList->words, sizeof(char*)*newSize);
if (NULL == newWords) {
return 0;
} else {
pWordList->size = newSize;
pWordList->words = (char**)newWords;
}
}
pWordList->words[nWords] = word;
++pWordList->nWords;
return 1;
}
char** word_list_start(word_list* pWordList) {
return pWordList->words;
}
char** word_list_end(word_list* pWordList) {
return &pWordList->words[pWordList->nWords];
}
int main(int argc, char** argv) {
word_list* myWords = create_word_list(2);
add_word_to_word_list(myWords, "Hello");
add_word_to_word_list(myWords, "World");
add_word_to_word_list(myWords, "Goodbye");
char** iter;
for (iter = word_list_start(myWords); iter != word_list_end(myWords); ++iter) {
printf("%s ", *iter);
}
delete_word_list(myWords);
return 0;
}
If you want to dynamically allocate arrays, you can use malloc from stdlib.h.
If you want to allocate an array of 100 elements using your words struct, try the following:
words* array = (words*)malloc(sizeof(words) * 100);
The size of the memory that you want to allocate is passed into malloc and then it will return a pointer of type void (void*). In most cases you'll probably want to cast it to the pointer type you desire, which in this case is words*.
The sizeof keyword is used here to find out the size of the words struct, then that size is multiplied by the number of elements you want to allocate.
Once you are done, be sure to use free() to free up the heap memory you used in order to prevent memory leaks:
free(array);
If you want to change the size of the allocated array, you can try to use realloc as others have mentioned, but keep in mind that if you do many reallocs you may end up fragmenting the memory. If you want to dynamically resize the array in order to keep a low memory footprint for your program, it may be better to not do too many reallocs.
This looks like an academic exercise which unfortunately makes it harder since you can't use C++. Basically you have to manage some of the overhead for the allocation and keep track how much memory has been allocated if you need to resize it later. This is where the C++ standard library shines.
For your example, the following code allocates the memory and later resizes it:
// initial size
int count = 100;
words *testWords = (words*) malloc(count * sizeof(words));
// resize the array
count = 76;
testWords = (words*) realloc(testWords, count* sizeof(words));
Keep in mind, in your example you are just allocating a pointer to a char and you still need to allocate the string itself and more importantly to free it at the end. So this code allocates 100 pointers to char and then resizes it to 76, but does not allocate the strings themselves.
I have a suspicion that you actually want to allocate the number of characters in a string which is very similar to the above, but change word to char.
EDIT: Also keep in mind it makes a lot of sense to create functions to perform common tasks and enforce consistency so you don't copy code everywhere. For example, you might have a) allocate the struct, b) assign values to the struct, and c) free the struct. So you might have:
// Allocate a words struct
words* CreateWords(int size);
// Assign a value
void AssignWord(word* dest, char* str);
// Clear a words structs (and possibly internal storage)
void FreeWords(words* w);
EDIT: As far as resizing the structs, it is identical to resizing the char array. However the difference is if you make the struct array bigger, you should probably initialize the new array items to NULL. Likewise, if you make the struct array smaller, you need to cleanup before removing the items -- that is free items that have been allocated (and only the allocated items) before you resize the struct array. This is the primary reason I suggested creating helper functions to help manage this.
// Resize words (must know original and new size if shrinking
// if you need to free internal storage first)
void ResizeWords(words* w, size_t oldsize, size_t newsize);
In C++, use a vector. It's like an array but you can easily add and remove elements and it will take care of allocating and deallocating memory for you.
I know the title of the question says C, but you tagged your question with C and C++...
Another option for you is a linked list. You'll need to analyze how your program will use the data structure, if you don't need random access it could be faster than reallocating.
Your code in the last update should not compile, much less run. You're passing &x to LoadData. &x has the type of **words, but LoadData expects words* . Of course it crashes when you call realloc on a pointer that's pointing into stack.
The way to fix it is to change LoadData to accept words** . Thi sway, you can actually modify the pointer in main(). For example, realloc call would look like
*x = (words*) realloc(*x, sizeof(words)*2);
It's the same principlae as in "num" being int* rather than int.
Besides this, you need to really figure out how the strings in words ere stored. Assigning a const string to char * (as in str2 = "marley\0") is permitted, but it's rarely the right solution, even in C.
Another point: non need to have "marley\0" unless you really need two 0s at the end of string. Compiler adds 0 tho the end of every string literal.
For the test code: if you want to modify a pointer in a function, you should pass a "pointer to pointer" to the function. Corrected code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct
{
char *str1;
char *str2;
} words;
void LoadData(words**, int*);
main()
{
words **x;
int num;
LoadData(x, &num);
printf("%s %s\n", (*x[0]).str1, (*x[0]).str2);
printf("%s %s\n", (*x[1]).str1, (*x[1]).str2);
}
void LoadData(words **x, int *num)
{
*x = (words*) malloc(sizeof(words));
(*x[0]).str1 = "johnnie\0";
(*x[0]).str2 = "krapson\0";
*x = (words*) realloc(*x, sizeof(words) * 2);
(*x[1]).str1 = "bob\0";
(*x[1]).str2 = "marley\0";
*num = *num + 1;
}
Every coder need to simplify their code to make it easily understood....even for beginners.
So array of structures using dynamically is easy, if you understand the concepts.
// Dynamically sized array of structures
#include <stdio.h>
#include <stdlib.h>
struct book
{
char name[20];
int p;
}; //Declaring book structure
int main ()
{
int n, i;
struct book *b; // Initializing pointer to a structure
scanf ("%d\n", &n);
b = (struct book *) calloc (n, sizeof (struct book)); //Creating memory for array of structures dynamically
for (i = 0; i < n; i++)
{
scanf ("%s %d\n", (b + i)->name, &(b + i)->p); //Getting values for array of structures (no error check)
}
for (i = 0; i < n; i++)
{
printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures
}
scanf ("%d\n", &n); //Get array size to re-allocate
b = (struct book *) realloc (b, n * sizeof (struct book)); //change the size of an array using realloc function
printf ("\n");
for (i = 0; i < n; i++)
{
printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures
}
return 0;
}
If you want to grow the array dynamically, you should use malloc() to dynamically allocate some fixed amount of memory, and then use realloc() whenever you run out. A common technique is to use an exponential growth function such that you allocate some small fixed amount and then make the array grow by duplicating the allocated amount.
Some example code would be:
size = 64; i = 0;
x = malloc(sizeof(words)*size); /* enough space for 64 words */
while (read_words()) {
if (++i > size) {
size *= 2;
x = realloc(sizeof(words) * size);
}
}
/* done with x */
free(x);
Here is how I would do it in C++
size_t size = 500;
char* dynamicAllocatedString = new char[ size ];
Use same principal for any struct or c++ class.

C Programming: malloc() for a 2D array (using pointer-to-pointer)

yesterday I had posted a question: How should I pass a pointer to a function and allocate memory for the passed pointer from inside the called function?
From the answers I got, I was able to understand what mistake I was doing.
I'm facing a new problem now, can anyone help out with this?
I want to dynamically allocate a 2D array, so I'm passing a Pointer-to-Pointer from my main() to another function called alloc_2D_pixels(...), where I use malloc(...) and for(...) loop to allocate memory for the 2D array.
Well, after returning from the alloc_2D_pixels(...) function, the pointer-to-pointer still remains NULL, so naturally, when I try accessing or try to free(...) the Pointer-to-Pointer, the program hangs.
Can anyone suggest me what mistakes I'm doing here?
Help!!!
Vikram
SOURCE:
main()
{
unsigned char **ptr;
unsigned int rows, cols;
if(alloc_2D_pixels(&ptr, rows, cols)==ERROR) // Satisfies this condition
printf("Memory for the 2D array not allocated"); // NO ERROR is returned
if(ptr == NULL) // ptr is NULL so no memory was allocated
printf("Yes its NULL!");
// Because ptr is NULL, with any of these 3 statements below the program HANGS
ptr[0][0] = 10;
printf("Element: %d",ptr[0][0]);
free_2D_alloc(&ptr);
}
signed char alloc_2D_pixels(unsigned char ***memory, unsigned int rows, unsigned int cols)
{
signed char status = NO_ERROR;
memory = malloc(rows * sizeof(unsigned char** ));
if(memory == NULL)
{
status = ERROR;
printf("ERROR: Memory allocation failed!");
}
else
{
int i;
for(i = 0; i< cols; i++)
{
memory[i] = malloc(cols * sizeof(unsigned char));
if(memory[i]==NULL)
{
status = ERROR;
printf("ERROR: Memory allocation failed!");
}
}
}
// Inserted the statements below for debug purpose only
memory[0][0] = (unsigned char)10; // I'm able to access the array from
printf("\nElement %d",memory[0][0]); // here with no problems
return status;
}
void free_2D_pixels(unsigned char ***ptr, unsigned int rows)
{
int i;
for(i = 0; i < rows; i++)
{
free(ptr[i]);
}
free(ptr);
}
One mistake is posting code that won't compile :). Below is corrected code with my comments in
/* this style */:
/* Next four lines get your code to compile */
#include <stdio.h>
#include <stdlib.h>
#define NO_ERROR 0
#define ERROR 1
/* prototypes for functions used by main but declared after main
(or move main to the end of the file */
signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols);
void free_2D_pixels(unsigned char** ptr, unsigned int rows);
/* main should return int */
int main()
{
unsigned char** ptr;
/* need to define rows and cols with an actual value */
unsigned int rows = 5, cols = 5;
if(alloc_2D_pixels(&ptr, rows, cols) == ERROR) // Satisfies this condition
printf("Memory for the 2D array not allocated"); // ERROR is returned
if(ptr == NULL) // ptr is NULL so no memory was allocated
printf("Yes its NULL!");
else
{
/* Added else clause so below code only runs if allocation worked. */
/* Added code to write to every element as a test. */
unsigned int row,col;
for(row = 0; row < rows; row++)
for(col = 0; col < cols; col++)
ptr[0][0] = (unsigned char)(row + col);
/* no need for &ptr here, not returning anything so no need to pass
by reference */
free_2D_pixels(ptr, rows);
}
return 0;
}
signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols)
{
signed char status = NO_ERROR;
/* In case we fail the returned memory ptr will be initialized */
*memory = NULL;
/* defining a temp ptr, otherwise would have to use (*memory) everywhere
ptr is used (yuck) */
unsigned char** ptr;
/* Each row should only contain an unsigned char*, not an unsigned
char**, because each row will be an array of unsigned char */
ptr = malloc(rows * sizeof(unsigned char*));
if(ptr == NULL)
{
status = ERROR;
printf("ERROR: Memory allocation failed!");
}
else
{
/* rows/cols are unsigned, so this should be too */
unsigned int i;
/* had an error here. alloced rows above so iterate through rows
not cols here */
for(i = 0; i < rows; i++)
{
ptr[i] = malloc(cols * sizeof(unsigned char));
if(ptr[i] == NULL)
{
status = ERROR;
printf("ERROR: Memory allocation failed!");
/* still a problem here, if exiting with error,
should free any column mallocs that were
successful. */
}
}
}
/* it worked so return ptr */
*memory = ptr;
return status;
}
/* no need for *** here. Not modifying and returning ptr */
/* it also was a bug...would've needed (*ptr) everywhere below */
void free_2D_pixels(unsigned char** ptr, unsigned int rows)
{
/* should be unsigned like rows */
unsigned int i;
for(i = 0; i < rows; i++)
{
free(ptr[i]);
}
free(ptr);
}
In your alloc_2D_pixels function, you need another level of indirection when accessing memory. As it is now, you only modify the parameter, not the pointer pointed to by the parameter. For example,
memory = malloc(rows * sizeof(unsigned char** ));
// becomes
*memory = malloc(rows * sizeof(unsigned char** ));
// and later...
memory[i] = malloc(cols * sizeof(unsigned char));
// becomes
(*memory)[i] = malloc(cols * sizeof(unsigned char));
(basically, anywhere you are using memory, you need to use (*memory); the parentheses are only needed when you are using subscripts to ensure that the operators are applied in the correct order)
It also looks like, You are using uninitialized rows and cols variables
Using multidimensional arrays in this way in C is "suboptimal" for performance.
In no unclear words: Please do not use - and definitely not initialize - multidimensional arrays in the way you've illustrated. Multiple calls to malloc() will create you a batch of disjoint memory locations that doesn't map well to how actual graphics (as contiguous, single buffers) are stored anywhere. Also, if you have to do it hundreds or thousands of times, malloc() can be hideously expensive.
Also, due to the fact that you're using malloc() very often, it's also a nightmare (and bug to bite you eventually) for cleaning up. You've even mentioned that in the comments in your code, and yet ... why ?
If you absolutely must have this ptr[rows][cols] thing, create it better like this:
signed char alloc_2D_pixels(unsigned char*** memory,
unsigned int rows,
unsigned int cols)
{
int colspan = cols * sizeof(char);
int rowspan = rows * sizeof(char*);
unsigned char **rowptrs = *memory = malloc(rowspan + rows * colspan));
/* malloc failure handling left to the reader */
unsigned char *payload = ((unsigned char *)rowptrs) + rowspan;
int i;
for (i = 0; i < rows; payload += colspan, i++)
rowptrs[i] = payload;
}
that way you're allocating only a single block of memory and the whole thing can be freed in one go - ditch free_2D_pixels().

Resources