I'm new in C programming (my main area is java) and in java there exists the ArrayList which I can make like
ArrayList<Class> arraylist = new ArrayList<Class>();
where my class Class can have several items, such as int, or string.
In c, I found I cannot do that but need to do something like that, so I did this
typedef struct vectorObject {
int myInt;
char *charPointer;
} vectorObject;
I define a pointer of my structure like this:
vectorObject *listVectorObject;
and using
#define MAX_FILE_SIZE 50000
when I want to allocate the memory of that, I use this:
int i;
listVectorObject = malloc(MAX_FILE_SIZE);
if (listVectorObject == NULL ) {
printf("Out of memory1\n");
exit(1);
}
for (i = 0; i < MAX_FILE_SIZE; i++) {
listVectorObject[i].charPointer= malloc(MAX_FILE_SIZE);
if (listVectorObject[i].charPointer == NULL ) {
printf("Out of memory2\n");
exit(1);
}
}
The problem is I always get a
Out of Memory2
I already tried everything and I cannot find where my mistake is. Could you please help me?
Thanks!!
I don't think you want 50000 vectorObjects each with 50000 bytes char-buffer.
So look at this:
first making a list of 1000 vectorObjects
then for each of those allocating a memory chunk to the char-pointer
.
int i, howmany= 1000;
vectorObject *listVectorObject = malloc(sizeof(vectorObject)*howmany); // list of 1000 vectorObjects
if (listVectorObject == NULL ) {
printf("Out of memory1\n");
exit(1);
}
// one file-size char-pointer for each vector object above
for (i = 0; i<howmany; i++) {
listVectorObject[i].charPointer= malloc(MAX_FILE_SIZE);
if (listVectorObject[i].charPointer == NULL ) {
printf("Out of memory2\n");
exit(1);
}
}
Related
I'm trying to create an array of pointers in C. Each value of the array should be a pointer to a struct (let's call it struct Type*).
Should i do
struct Type* myVariable= malloc(sizeof(struct Type*)*MY_SIZE);
or
struct Type** myVariable= malloc(sizeof(struct Type*)*MY_SIZE);
The second one looks like what i should do when i want to create a two dimensional array, which are an array of pointer, and those pointers are used to create arrays of the wanted type.
EDIT : But in my case the second dimension size would be only one
The first one looks like a regular array with int* as the contained values type.
How can i pass the good solution to a function (by pointer, not by value because the array may be fairly large) and use it in the fonction ?
The second one the right solution. However, you'll need to allocate memory for the objects too. Also, make sure to check the value returned by malloc.
// Allocate memory for the array of pointers.
struct Type** myVariable = malloc(sizeof(struct Type*)*MY_SIZE);
if ( myVariable == NULL )
{
// Deal with error
exit(1);
}
for (int i = 0; i < MY_SIZE; ++i )
{
// Allocate memory for the array of objects.
myVariable[i] = malloc(sizeof(struct Type)*THE_SIZE_IN_THE_OTHER_DIMENSION);
if ( myVariable[i] == NULL )
{
// Free everything that was allocated so far
for (int j = 0; j < i-1; ++j )
{
free(myVariable[j]);
}
free(myVariable);
// Exit the program.
exit(1);
}
}
However, if THE_SIZE_IN_THE_OTHER_DIMENSION is going to be 1, you are better off using your first approach.
struct Type* myVariable = malloc(sizeof(struct Type)*MY_SIZE);
// ^^^^^^^^^^^ Drop the *
if ( myVariable == NULL )
{
// Deal with error
exit(1);
}
Neither!
Use an idiom that reduces work and errors
pointer = malloc(sizeof *pointer * Number_of_elements);
Or in OP's case "to create an array of pointers in C"
#define ARRAY_N 100
struct Type **myVariable = malloc(sizeof *myVariable * N);
if (myVariable == NULL) Handle_OutOfMemmory();
Now set those pointers to some value
#define M 50
size_t i;
for (i=0; i<N; i++) {
myVariable[i] = malloc(sizeof *(myVariable[i]) * M);
if (myVariable[i] == NULL) Handle_OutOfMemmory();
for (size_t m = 0; m<M; m++) {
// Initialize the fields of
myVariable[i][m].start = 0;
myVariable[i][m].value = 0.0;
myVariable[i][m].set = NULL;
}
}
I have this function. As you can see, everything is being done in the function, I'm not allocating in the main and then passing anything to it (I'll only return the pointer to the array once the function is done). The function in itself (with a fixed size for the array) works, but the realloc fails.
struct database *parse() {
int i = 0;
int n = 1;
FILE *dbase = (fopen(PATH, "r"));
if (dbase == NULL) {
fprintf(stderr, ERRORE_APERTURA);
exit(EXIT_FAILURE);
}
struct database *database_array = calloc(20*n, sizeof(struct database));
if (database_array == NULL) {
fprintf(stderr, "Impossibile allocare memoria\n");
exit(EXIT_FAILURE);
}
while (feof(dbase) == 0) {
fscanf(dbase, "%[^:]:%[^:]:\n", database_array[i].user, database_array[i].password);
database_array[i].iswritten = 1;
i++;
if (i > 20*n) {
n++;
struct database *new_database_array = realloc(database_array, sizeof(struct database)*(20*n));
database_array = new_database_array;
}
}
database_array[++i].iswritten = 0;
fclose(dbase);
return database_array;
}
I tried reading other explanations, but I can't understand what's wrong here.
The array I allocated with calloc is initially 20. then, when it's filled, I want it to double in size, so I use n, which will be 2, by 20, so 40.
The frustrating thing is that I tried reallocating an array of struct with a simpler program, and doing THE SAME THING works without any problem:
#include <stdio.h>
#include <stdlib.h>
struct prova {
int a;
int b[10];
};
int main() {
struct prova* array_struct = calloc(10, sizeof(struct prova));
array_struct[0].a = 2;
struct prova* tmp = realloc(array_struct, sizeof(struct prova) * 20);
free(array_struct);
array_struct = tmp;
array_struct[1].b[1] = 3;
printf("a = %d", array_struct[0].a);
printf("b = %d\n", array_struct[1].b[1]);
return 0;
}
What am I not seeing? (Please nevermind the fact that I'm not checking if realloc returns NULL, I'll add that later)
struct database *new_database_array = realloc(database_array, sizeof(struct database)*(20*n));
free(database_array);
You can't both reallocate something and deallocate it. You can do either, but once you've done either, the previous allocation no longer exists, so you can't do the other.
After the first line of code above, the value of database_array should not be used anymore because it may not be valid.
Basically I have two structs and I want to make an array of A structs, and within each A struct I want an array of 50 B structs. So I assume that we will use double pointers.
struct A{
char* a_word;
struct B** b_list;
};
struct B{
char* b_word;
int b_value;
};
When call initialize function I initialize the structs like this. My goal is to set all the values to NULL when I allocate memory.
struct Word** initialize()
{
int k;
int i;
struct A** A_list = calloc(BUFFSIZE, sizeof(struct A*));
for(k =0; k < BUFFSIZE; k++)
{
A_list[k] = calloc (1, sizeof(struct A));
A_list[k]-> b_list = calloc(50, sizeof(struct B*));
for(i = 0; i < 50; i++)
{
A_list[k]->b_list[i] = calloc(1, sizeof(struct B));
}
}
return hashTable;
}
after initializing all these values I am able to do. . .
if(A[43]->a_word == NULL) //43 unallocated value
{
printf("This is null\n");
//program prints this statement - good
//program knows that this value is NULL
}
But I also want . .
if(A_list[44]->b_list[0] == NULL)
{
printf("This is also null");
//This should be printed but nothing happens
}
For some reason not matter if I set the above if statement to == NULL or != NULL the program outputs absolutely nothing from that if statement. What is going on in memory and how can I allocate everything correctly, and so the value is set to NULL as a default and so I can input a value?
EDIT: Also whenever try to do A_list[value1]->b_list[value2] = strdup("string"); I get a segmentation error, this most likely stems from the same problem.
As mentioned already by WhozCraig in a comment to the question, this code
for(i = 0; i < 50; i++)
{
A_list[k]->b_list[i] = calloc(1, sizeof(struct B));
initialises the first 50 elements of b_list to point to valid memory, that is to be non 0, assuming calloc() never fails. Being that optimistic you better test for those elements being != NULL.
... if I set the above if statement to == NULL or != NULL the program outputs absolutely nothing
The code does not seem to flush stdout here:
if(A_list[44]->b_list[0] == NULL)
{
printf("This is also null");
Change this by adding a final \n:
if(A_list[44]->b_list[0] != NULL)
{
printf("This isn't null\n");
As stdout is line buffered by default, all content will be flushed if a new-line is detected.
I've got two different arrays that I'm using. With one, I'm getting the exact results that I want, the other, not so much. I'm filing the arrays with by reading from a text file similar to this:
2597
283
4
723
21
82
426
The first five lines would be the customer IDs. There is always 5 lines but they don't always have a value. The next line is the number of vendors, then followed by the vendor ids.
void use_arrays()
{
int
i,
customer_count,
*customer_ids,
vendor_count,
*vendor_ids;
customer_ids = malloc(sizeof(int));
vendor_ids = malloc(sizeof(int));
fill_arrays(&customer_count, customer_ids, &vendor_count, vendor_ids);
for (i = 0; i < customer_count; i++)
{
printf("Customer[%d]: %d\n", i, customer_ids[i]);
}
for (i = 0; i < vendor_count; i++)
{
printf("Vendor[%d]: %d\n", i, vendor_ids[i]);
}
free(customer_ids);
free(vendor_ids);
}
void fill_arrays(int *customer_count, int *customer_ids, int *vendor_count, int *vendor_ids)
{
int
i,
*temp,
customer_id,
vendor_id,
num_cust = 0;
FILE
*inp_file;
char
*endptr = NULL,
buffer[500];
inp_file = fopen(g_filename, "r");
for (i = 0; i < 5; i++) /* Can't be more than 5 customers */
{
fgets(buffer, sizeof(buffer), inp_file);
customer_id = strtol(buffer, &endptr, 0);
if (customer_id != 0)
{
customer_ids[i] = customer_id;
temp = realloc(customer_ids, (i+2)*sizeof(int));
if (temp != NULL)
{
customer_ids = temp;
}
else
{
printf("Couldn't allocate memory\n");
}
num_cust++;
}
}
*customer_count = num_cust;
/* Next is number of vendor ids*/
fgets(buffer, sizeof(buffer), inp_file);
*vendor_count = strtol(buffer, &endptr, 0);
temp = realloc(vendor_ids, *vendor_count*sizeof(int));
if (temp != NULL)
{
vendor_ids = temp;
}
else
{
printf("Couldn't allocate memory\n");
}
for (i = 0; i < *vendor_count; i++)
{
fgets(buffer, sizeof(buffer), inp_file);
vendor_id = strtol(buffer, &endptr, 0);
if (vendor_id != 0)
{
vendor_ids[i] = vendor_id;
}
}
fclose(inp_file);
}
Once the arrays print out, customer_ids is showing the correct numbers but vendor_ids is printing out random numbers from memory. To be more frustrating, it prints the vendors correctly from inside fill_arrays.
If you want to modify vendor_ids the way you do in fill_arrays, then you have to pass it in as a pointer to a pointer:
fill_arrays(int *customer_count, int *customer_ids, int *vendor_count, int **vendor_ids)
Call it like this:
fill_arrays(&customer_count, customer_ids, &vendor_count, &vendor_ids);
Then you can realloc like so:
temp = realloc(*vendor_ids, *vendor_count*sizeof(int));
if (temp != NULL)
{
*vendor_ids = temp;
}
Also, at the end of your function:
vendor_ids[i] = vendor_id;
will have to change to
(*vendor_ids)[i] = vendor_id;
You will also have to make the same changes to customer_ids. The fact that customer_ids was working while vendor_ids wasn't was probably due to your use of realloc. If realloc decides that the memory block has to be reallocated in a new location, you'll run into these problems but if reallocates the memory in the same location, your pointer that you passed in is still pointing there. Since you never know if realloc is going to make that descision or not, both customer_ids and vendor_ids should be passed in as pointers to pointers.
You seem a bit confused how to return memory from a function.
if you have a function that looks like this
void foo(int a);
you can not change a inside of foo, foo only gets a copy of a.
void foo(int *a);
otoh gives foo the address of a, i.e. "i know where you live" it lets you change what a points to. if a points to an array then you can change the contents of that array, if a points to a single integer you can change that.
void foo(int **a);
lets you change not only what a points to, but also where it points. so if you want a to point to somewhere else you can. this is what you need in your function, if you do a malloc/calloc/realloc in your function to return the result you need this
The following code is not working correctly. I'm getting a segfault when I run the program. I ran my program through gdb and found out that the error is occuring in the fillArrays(int**,int) function.
GDB is displaying the following parameters for fillArrays(int**,int):
fillArrays (arrays=0x0,numArrays=3)
Here is the source code to my program
#include <stdlib.h> /* malloc and free */
#define MULTIPLIER 1
#define SMALL 10
#define BIG 20
void allocateSmallArrays(int **arrays,int numArrays) {
int index,freeIndex;
int outerIndex,innerIndex;
arrays = malloc(numArrays*sizeof(int*));
if(arrays == NULL) {
printf("out of memory\n");
exit(1);
}
for(index = 0;index < numArrays;index++) {
arrays[index] = malloc(SMALL*sizeof(int));
if(arrays[index] == NULL) {
printf("out of memory\n");
exit(1);
}
}
}
void fillArrays(int **arrays,int numArrays) {
int outerIndex,innerIndex;
for(outerIndex = 0;outerIndex < numArrays;outerIndex++) {
for(innerIndex = 0;innerIndex < SMALL;innerIndex++)
arrays[outerIndex][innerIndex] = 0;
}
}
void deallocateSmallArrays(int **arrays,int numArrays) {
int index;
for(index = 0;index < numArrays;index++)
free(arrays[index]);
free(arrays);
}
int main(void) {
int numArrays = (3 * MULTIPLIER);
int **arrays = 0;
allocateSmallArrays(arrays,numArrays);
fillArrays(arrays,numArrays);
deallocateSmallArrays(arrays,numArrays);
arrays = 0;
return 0;
}
I was under the assumption that since arrays was allocated in allocateSmallArrays, that passing it through fillArrays would 0 out the allocated arrays and then deallocate in the last function. How do I go about accomplishing this?
The problem is that allocateSmallArrays changes its own copy of the arrays pointer. So the result of the malloc is lost and after the function is done, in the caller arrays is still 0. You could:
Pass a triple pointer int ***arrays and do to *arrays everything you're doing to arrays
Return the pointer instead of void
A C FAQ deals with this very subject.