As a spin of of an earlier question, I have run into some problems regarding allocating memory to a 3 dimensional array.
I am working on a project where we need to do some work on a text. To do this, we need to split the text into smaller sections, and process the text word for word. To save these smaller pieces of text, we have a 3D array, a list of sections each containing a list of the words in the section.
But I get a segmentation fault when I try to allocate memory for the individual words using malloc().
localText->list[i][n] = malloc(100 * sizeof(char));
Here is the entire code.
typedef struct {
char name[100];
char ***list;
}text;
int main(){
int i = 0, n, z,wordCount, sections;
FILE *file;
text *localText;
openFile(&file, "test.txt");
wordCount = countWords(file);
sections = (wordCount / 50) + 1;
localText = malloc(sizeof(text));
localText->list = malloc(sections * sizeof(char **));
for(i = 0; i < sections; i++)
localText->list[i] = malloc(50 * sizeof(char *));
for(n = 0; n < 50; n++)
localText->list[i][n] = malloc(100 * sizeof(char));
readFileContent(file, localText->list, 50);
freeText(localText);
return 1;
}
You're missing some braces:
for(i = 0; i < sections; i++) {
// ...
}
Related
Working with C, I am trying to read from a .txt file, line by line, and then put every line into an array. Every line is 200 characters long maximum, and the array can store, lets say 50 lines. If the number of lines exceed 50, I want to dynamically allocate twice as much memory, and so on until it is enough. If I put the if{...} part outside of the while loop, it seems to work, but as soon as I use it inside of the loop it does not. I would appreciate any help.
FILE *fp=fopen(file,"r");
int idx=0;
int row=50;
int col=300;
char temp[row][col];
while (fgets(temp[idx],col,fp)){
if (idx == row) {
char **new = malloc(2 * row * sizeof(char *));
for (int j = 0; j < row; j++) {
new[j] = (char *) malloc(col * sizeof(char) + 1);
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < (col + 1); j++) {
new[i][j] = temp[i][j];
}
}
row = 2 * row;
**temp = **new;
free(new);
}
idx++;
}
fclose(fp);
You cannot change the dimensions of a local array (here temp[row][col]). Instead you need to keep a pointer to such an array. In the following code I use a temp array just to keep one line for fgets, and then copy it immediately into a dynamically allocated storage (arr is the 2d array of lines):
FILE *fp=fopen(file,"r");
int idx=0;
int row=50;
int col=300;
char temp[col];
char **arr = malloc(row*sizeof(char*));
while (fgets(temp,col,fp)){
if (idx == row) {
char **new = realloc(arr, 2 * row * sizeof(char *));
if(!new) abort();
arr = new;
row *= 2;
}
arr[idx++] = strdup(temp);
}
fclose(fp);
If I have int **array and want to place a series of numbers in it (I don't know its size), 5 3 4 0 or 9 1 5 8 3 0 as an example. As far as I know I should be using malloc
So I did something like this
int **array;
int n = 1, inp = 0;
while(n){ // scan till the input is 0
scanf("%d", &n);
array = (int**)malloc(sizeof(int*)*(inp+1)); //since inp start at 0
array[inp] = &n; //is this even correct?
inp++;
}
My first question is: Will this method (the loop) upgrade/expand the size of the array or is what I am doing a waste of memory?
The second question is how can I print/edit the values of this array?
EDIT:
From your answers I have came up with the following.
int **array;
int n = 1, inp = 0;
array = (int**)malloc(sizeof(int*));
while(n){
scanf("%d", &n);
realloc( array, sizeof((int*)(inp+1)));
array[inp] = n;
inp++;
}
Is this the correct way to do it?
Note* I am aware that it does not have to be a pointer of a pointer, but I need it to be for something else later on.
You code is wrong for at least these reasons.
1) You keep doing malloc to array and thereby loose previously malloced blocks. The function to use is realloc when extending the size of dynamic memory.
2) You store the address of n instead of the value of n
Besides that it seems strange to use a double pointer. Why not do like:
int *array = NULL;
int n = 1, inp = 0;
while(n){ // scan till the input is 0
scanf("%d", &n);
array = realloc(array, sizeof(int)*(inp+1));
array[inp] = n;
inp++;
}
EDIT after OPs update
If you really want to use a double pointer (i.e. int **array;), you need to allocate memory in two levels.
That could look like:
int **array = malloc(sizeof *array);
*array = NULL;
int n = 1, inp = 0;
while(n){ // scan till the input is 0
scanf("%d", &n);
*array = realloc(*array, sizeof(int)*(inp+1));
(*array)[inp] = n;
inp++;
}
What you're doing in your code is allocating progressively larger areas of memory and saving the input value in the last position of each new area, while losing the pointers to the previously allocated areas. A commom and efficient solution for what you want (which is used in C++'s vectors, I believe) is to allocate some minimum amount of space, then check at each iteration if you are on the verge of exceeding it. In case you are, reallocate the area doubling the space. Something like this:
int i = 0; //iterator
int s = 1; //array size
int n; //input (use do-while so you don't have to worry about initial value)
//it doesn't have to be bidimensional for a single series
int * array = (int *) malloc(sizeof(int) * s);
do
{
if(i == s)
{
s *= 2;
array = (int *) realloc(array, sizeof(int) * s);
}
scanf("%d", &n);
array[i++] = n; //assign with the value, not with the address
}
while(n)
UPDATE: if you really need to use **int, do it like this:
int n, i = 0, s = 1;
int ** array = (int **) malloc(sizeof(int*) * s);
do
{
if(i == s)
{
s *= 2;
array = (int **) realloc(array, sizeof(int *) * s);
}
scanf("%d", &n);
array[i] = (int *) malloc(sizeof(int));
array[i][0] = n;
++i;
}
while(n)
I want to make an array of strings in which I don't have a fix lenght for every string. How do i do it?
This is my code:
char **a;
int n, m;
scanf_s("%d %d", &n, &m);
a = (char**)malloc(n*sizeof(char*));
for (int i = 0; i < n; i++)
a[i] = (char*)malloc(m*sizeof(char));
for (int i = 0; i < n; i++)
for (int j = 0; j < m;j++)
scanf_s(" %c", &a[i][j])
I have to input an array of words and i don't know the lenght for them. In this code I can input only words of a certain lenght and I want to change that.
An example of what #Daniel says is:
int NumStrings = 100;
char **strings = (char**) malloc(sizeof(char*) * NumStrings);
for(int i = 0; i < NumStrings; i++)
{
/*
Just an example of how every string may have different memory allocated.
Note that sizeof(char) is normally 1 byte, but it's better to let it there */
strings[i] = (char*) malloc(sizeof(char) * i * 10);
}
If you don't need to malloc every string at the beginning, you can do it later. If you need to change the number of strings allocated (do a realloc to strings), then it might be slightly more complicated.
Allocate an array of strings char ** mystrs = malloc(numstrings * sizeof(char *)). Now mystrs is an array of pointers. Now all you need to do is use malloc for each string you want to add.
mystrs[0] = malloc(numchars +1 * sizeof(char)). // add extra char for null character
Then you can copy the string data with strcpy.
strcpy(mystrs[0], "my string")
I have a project where I create a 2D char array that stores words, with the option to add more words, and then resize the array when necessary. I'm getting a variety of errors as I try to play with it and fix it so now I think I need some extra eyes on my code. I'm specifically looking for anything that obviously stands out as an incorrect or troublesome way of allocating memory or initializing an array.
The error I am getting specific to this code says "free(): invalid pointer" and leads to a SIGABRT. Below is my code.
Here is my resize function.
char ** resize_array(char **array)
{
int i;
char** tmp = malloc(2 * sizeof(*array));
int j;
for(j = 0; j < (2 * sizeof(*array)); j++)
tmp[j] = malloc(2 * sizeof(*array));
for(i = 0; i < (sizeof *words); i++)
{
strcpy(tmp[i], words[i]);
}
for(i = 0; words[i] != NULL; i++)
free(words[i]);
free(words);
return tmp;
}
Here is my resize function being implemented
int len;
len = (sizeof words);
if(upperbound > len) //upperbound keeps track of the word count
//and resizes the array
{
char **tmp = resize_array((char **) words);
int i;
for(i = 0; i <= upperbound; i++)
strcpy(words[i], tmp[i]);
}
And finally here is the "words" array as it is initially initialized.
char words[14][50];
I'm using VI and running everything on Ubuntu just fyi. Thanks in advance for everyones help!
Inside the resize_array function, you can't determine the previous size of the array using only a pointer to it.
The call to malloc
malloc(2 * sizeof(*array))
requests an allocation twice the size of a pointer to a char (only 16 bytes on a 64bit machine).
This is the first problem you need to fix.
I need to allocate a char** array that points to a 2 dimensions chars array.
Eventually, I want to point to a "cell" like players[playerNum][Row][Col].
This is what I wrote so far, but it fails.
It is hard to understand the logic behind it, so if you can explain me whats wrong it will be great.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int numOfPlayers;
int i,j;
char** players = (char **)malloc(sizeof(char**)*numOfPlayers); // players array
for (i=0 ; i<numOfPlayers ; i++){
players[i] = (char *)malloc(sizeof(char*)*10); // each player 1st D array
}
for (i=0 ; i<10 ; i++){
for (j=0 ; j<10 ; j++){
players[i][j] = (char *)malloc(sizeof(char*)*10);
}
}
return 0;
}
Allocation in your code is wrong!
Do like this:
char** players = malloc(sizeof(char*) * numOfPlayers);
^ remove one *
for (i=0 ; i<numOfPlayers ; i++){
players[i] = malloc(sizeof(char)* 10); // each player 1st D array
// ^ remove * it should be char
}
note: sizeof(char) != sizeof(char*).
You don't need second nested for loop too. (just above code is fine)
Also avoid casting return value from malloc/calloc in C
Note A mistake in your code is that numOfPlayers is not initialized (you are trying with garbage value).
Comment:
But then, i only have 2D array. i need an array that each cell of him points to a 2D array like so... you misunderstood my question
Read if you wants - a matrix of String or/ 3D char array
To allocate a matrix like: players[playerNum][Row][Col]
char ***players;
players = calloc(playerNum, sizeof(char**));
for(z = 0; z < playerNum; z++) {
players[z] = calloc(Row, sizeof(char*));
for(r = 0; r < Row; r++) {
players[z][r] = calloc(Col, sizeof(char));
}
}
Edit If you wants to allocate continues memory for data, then you can use following technique. It will also be preferable because it makes less call of malloc function.
char *players_data, // pointer to char
***players; // pointer to 2D char array
players_data = calloc(playerNum * Row * Col, sizeof(char)); //1 memory for elements
players = calloc(playerNum, sizeof(char **)); //2 memory for addresses of 2D matrices
for(i = 0; i < playerNum; i++){
players[i] = calloc(Row, sizeof(char*)); //3 memory for data cols
for(r = 0; r < Row; r++){ //4 Distributed memory among rows
players[i][r] = players_data + (i * Row * Col) + (r * Col);
}
}
A good reference to learn: Dynamic Three Dimensional Arrays in C\C++