2d dynamic allocation - c

I want to allocate dynamic an array of chars. So i ve the above code
void initialize(char **document_table, int size){
int x, i, j, M;
printf("how many words every line: "); scanf("%d", &M);
document_table = malloc(sizeof(char) * size);
for(x = 0; x < size; x ++) {
document_table[x] = malloc(sizeof(char) * M);
}
for(i=0; i<N; i++){
for(j=0; j<N; j++){
scanf("%c",&document_table[i][j]);
}
}
}
but it seems that after the allocation of the memory the function stop working.

The declaration document_table = malloc(sizeof(char) * size); should have sizeof(char*), since a 2D array is an array of pointers to 1D arrays.

Issue 1: char** document_table is itself passed by value. This means that calling code such as:
char** document_table = 0;
initialize(document_table,2);
/* document_table still 0 here */
will not initialise the passed parameter. Likely want to make the document_table the return value, or pass in its address.
Issue 2: N should be size?
Issue 3: scanf("%c") is inconsistent with the definition of M being "words". %c represents single characters. Also, the text every line implies line oriented input, but again this is not what the scanning looks for. If the document stores "words" then:
a document is an array of lines
a line is a array of words
a word is an array of characters
So a document is actually a 3D array of characters.

You should allocate pointers in your array:
document_table = malloc(sizeof(char*) * size);
Notice the char* in the sizeof() operator

Related

Why isn't scanf storing integers in the right array location?

I'm creating a dynamically allocated two dimensional int array and trying to use scanf to read user input directly to it, however this doesn't work properly. The first read is correct and stores the user entered value at [0][0], but the second read stores the value at [1][0] instead of [0][1], and the third and subsequent reads don't store the values anywhere in the array (I guess ending up in random memory outside the bounds?). It seems like the indices are wrong, but I've double checked them and can see the correct values for them in the debugger.
#include <stdio.h>
#include <stdlib.h>
#define ROW_SIZE 2
#define COL_SIZE 6
typedef int myMatrix[ROW_SIZE][COL_SIZE];
int main(void) {
myMatrix *pMatrix = (myMatrix *)malloc(sizeof(int) * (ROW_SIZE * COL_SIZE));
for (int i = 0; i < ROW_SIZE; ++i) {
for (int j = 0; j < COL_SIZE; ++j) {
printf("Enter row %d column %d: ", i, j);
scanf("%d", pMatrix[i][j]);
}
}
// Do stuff with matrix
return 0;
}
If I read the user input into a temp int and then write that to the de-referenced array pointer it works fine:
int temp = 0;
for (int i = 0; i < ROW_SIZE; ++i) {
for (int j = 0; j < COL_SIZE; ++j) {
printf("Enter row %d column %d: ", i, j);
scanf("%d", &temp);
(*pMatrix)[i][j] = temp;
}
}
What am I doing wrong with scanf and the 2d array pointer?
pMatrix is a pointer to a 2D array.
So pMatrix[0] will bring you to the first allocated 2D array,
and pMatrix[1] will bring you to the second allocated 2D array,
and pMatrix[2] will bring you to the third allocated 2D array,
and so on.
In your code you only allocate one 2D array so accessing pMatrix[1], pMatrix[2], ... is illegal as it is outside the allocated memory.
In other words
scanf("%d", pMatrix[i][j]);
is wrong. You need an extra dereference to get to the individual integers and a & to take its address so that it can be used in scanf.
You can do:
scanf("%d", &pMatrix[0][i][j]); // [0] because you only allocate 1 2D array
or
scanf("%d", &(*pMatrix)[i][j]); // (*pMatrix) works just like pMatrix[0]
// The ( ) is important due to
// operator precedence.
They are the same.

2D array as pointer to char array

I am playing with some code in C and also I am trying to understand relationship between pointers and arrays. As you probably know, when I want to make array it could be done like this:
char * arr = "abc";
or
char arr[] = {'a','b', 'c'};
But when I want to do 2D array. It must be done like this
char arr[3][10];
Why declaration like this crashes when I try to load string to that.
char * names[3];
for ( int i = 0; i < 3; i++ ) {
printf("Enter name %d: ", i+1 );
scanf("%s", names[i]);
}
// print names
printf("\nEntered names are: \n");
for ( int i = 0; i < 3; i++ ) {
printf("%s\n", names[i] );
}
It should be 2D array right? Because array is basically pointer.
Could you please explain that?
Thanks.
char * names[3];
Is not a 2D array, it's an array of three pointers to char, if you want to store char arrays in it you must allocate memory to each individual pointer, something like:
for(size_t i = 0; i < 3; i++){
names[i] = malloc(/*length your array of chars*/);
}
You can then store char arrays, using you example:
for(size_t i = 0; i < 3; i++){
printf("Enter name %ld: ", i + 1 );
scanf("%29s", names[i]); //for a malloc size of 30
}
Note that you must be careful with scanf, if the inputed string is longer then the memory allocated to store it you will have stack smashing, i.e. for names[i] with size of 30, you should use %29s specifier, instead of %s. Though this approach is not whitout its issues, namely possible characters left in stdin buffer, it's definitely safer.
Alternatively you can assign them string literals (in this case it's best to declare the array as const, otherwise if you try to edit one or more characters it'll result in a segfault):
const char* names[3];
for(size_t i = 0; i < 3; i++){
names[i] = "My string literal";
}
You can also make them point to existing char arrays:
char arr[3][10];
char* names[3];
for(size_t i = 0; i < 3; i++){
names[i] = arr[i];
}
char * names_1[3];
It's not a pointer. It's an array of pointers.
char names_2[3][10]={"one", "two", "three"};
char (*p_names_2)[10]=names_2;
Now it's a pointer to your 2D-Array. Just define a function and try to use it with your "pointers" as parameters.
void print_names(char names[][10], const int row){
for(int i=0; i<row; i++)
puts(names[i]);
}
Now call it with:
print_names(names_2, 3);
print_names(p_names_2, 3);
print_names(names_1, 3); //WRONG
And you'll see the difference.
char* names[3] is not strictly a 2D array (they don't exist in C or C++); it's an array of arrays. So each element of names contains simply a char*, which has not been initialised.
Note also that a c-style string is a null-terminated array of chars, so your original arr is not a c-style string. To make it a c-style string you would need:
char arr[] = {'a','b','c',0};
making it an array of length 4, not 3.
Missing off the null-terminator will mean that most functions will run off the end of the allocated memory, because they won't know when the string stops.
pointer is a type of variable, which can only contain an address of another variable. It can't contain any data. You can't store data into a pointer.Pointers should point at memory location.
So to use a pointer in the right way ,it must always point at a valid memory location in stack or memory dynamically allocated in heap.
this char * names[3] is an array of pointers ,so you need to reserve memory for it and then initialize it.You need to use some thing like this:
char *name[3];
for(int i=0;i<3;i++)
{
name[i]=malloc(strlen(string)+1);
}
also you should allocate memory for char *arr too.
char *arr=malloc(strlen(data)+1)
then initialized it.

Segmentation fault using scanf for float ** type

I'm trying to code a function that would ask the user to enter matrix. It prompts the number of lines, the number of columns and then prompts the value for each element of the matrix:
#include <stdio.h>
#include <stdlib.h>
void enterMatrix(float ** matrix, int nbLines, int nbColumns){
for (int i = 0; i < nbLines * nbColumns; i++){
printf("i = %d? ", i);
scanf("%f", matrix[i]);
}
}
int main(void){
int nbLines, nbColumns;
printf("nbLines? "); scanf("%d", &nbLines);
printf("nbColumns? "); scanf("%d", &nbColumns);
float *matrix[nbL * nbCol];
enterMatrix(matrix, nbLines, nbColumns);
}
Everything works fine until I enter a value for i = 0 and then press enter, which leads to a segmentation fault.
Any idea as to what could be wrong?
Your problem is because
float *matrice[nbL * nbCol];
defines an array of uninitialised pointers (i.e. an array of float *), not an array of float. This is then passed to enterMatrix() as a pointer to pointer to float (i.e. a float **). The scanf() calls then read to matrix[i] which is an uninitialised pointer. The result is undefined behaviour.
One fix would be to change the definition of matrice in main() to
float matrice[nbL * nbCol];
and change the function to (I've used comment to highlight changes)
void enterMatrix(float *matrix, int nbLines, int nbColumns) /* note type of matrix */
{
for (int i = 0; i < nbLines * nbColumns; i++)
{
printf("i = %d? ", i);
scanf("%f", &matrix[i]); /* note what the second argument is */
}
}
You need to allocate memory dinamically since you do not know at compile time which values the variables nbLines and nbColumns will hold.
So you need to first declare the pointer to the matrix:
float **matrix;
Then start allocate memory according to user input:
matrix = (float **)malloc(nbLines * sizeof(float *));
for (int i = 0; i < nbLines; i++)
{
matrix[i] = (float *)malloc(nbColums * sizeof(float ));
}
The segmentation fault error happens becouse you are not allocating memory for your matrix, but just a [nbL * nbCol] pointers to float
You don't allocate enough memory for your array, thus you invoke Undefined Behavior, since you go out of bounds, causing a Segmentation fault.
You could declare it like a 2D array, like this:
/* TODO: Check if allocation succeeded. (check for NULL pointer) */
float** matrix;
matrix = malloc(nbLines * sizeof(float*));
for(int i = 0 ; i < N ; i++)
matrix[i] = malloc(nbColumns * sizeof(float));
I have other approaches for allocating a 2D array dynamically here.
Please note: Do I cast the result of malloc? No!
Also do not forget to free().
You could emulate a 2D array with an 1D array, like this:
void enterMatrix(float* matrix, int nbLines, int nbColumns){
for (int i = 0; i < nbLines ; i++) {
for (int j = 0; j < nbColumns; j++) {
scanf("%f", matrix[i + nbColumns * j]);
}
}
float matrix[nbLines * nbColumns];
You're creating a variable length array, and, of pointers.
While other answers are perfectly valid, if you really want a 2D array, you just need to change the declaration:
float matrix[nbLines][nbColumns];
to declare a 2D variable length array of floats.
Now the hard point is to pass this VLA to a function and preserve dimensions.
For that you could use C99 way of passing VLAs (note that dimensions must be located before the VLA itself). Reference: Passing a multidimensional variable length array to a function:
void enterMatrix(int nbLines, int nbColumns, float matrix[][nbColumns] ){
for (int i = 0; i < nbLines; i++){
for (int j = 0; j < nbColumns; j++)
{
scanf("%f", &matrix[i][j]);
}
}
}
call as follows:
enterMatrix(nbLines, nbColumns, matrix);

How to dynamically allocate an array of strings in C?

I'm a noob so don't be hard on be.
Instead of something like this;
char string[NUM OF STRINGS][NUM OF LETTERS];
Is it possible to dynamically allocate how many strings will be in the array with malloc just like when you dynamically allocate memory for char pointer? Something like this:
int lines;
scanf("%d", &lines);
char *string[NUM OF LETTERS]
string = malloc(sizeof(char) * lines);
I tried it but it doesn't work; There must be something I'm doing wrong.
The other solution I thought of was:
int lines;
scanf("%d", &lines);
char string[lines][NUM OF LETTERS];
but I want to know if that's possible using malloc.
You can also use malloc for each word, like this
char **array;
int lines;
int i;
while (scanf("%d", &lines) != 1);
array = malloc(lines * sizeof(char *));
if (array != NULL)
{
for (i = 0 ; i < lines ; ++i)
{
int numberOfLetters;
while (scanf("%d", &numberOfLetters) != 1);
array[i] = malloc(numberOfLetters);
}
}
where numberOfStrings and lengthOfStrings[i] are integers that represent the number of strings you want the array to contain, an the length of the ith string in the array respectively.
You have two methods to implement this.
First is more complicated, cause it requires the allocation of memory for array of pointers to strings, and also allocation of memory for each string.
You can allocate the memory for entire array:
char (*array)[NUM_OF_LETTERS]; // Pointer to char's array with size NUM_OF_LETTERS
scanf("%d", &lines);
array = malloc(lines * NUM_OF_LETTERS);
. . .
array[0] = "First string\n";
array[1] = "Second string\n";
// And so on;
A disadvantage of the second method is that NUM_OF_LETTERS bytes are allocated for each string. So if you has many short strings, the first method would be better for you.
In case you want contiguous memory allocation:
char **string = malloc(nlines * sizeof(char *));
string[0] = malloc(nlines * nletters);
for(i = 1; i < nlines; i++)
string[i] = string[0] + i * nletters;
For more detailed explanation: Read FAQ list ยท Question 6.16.
int lines;
scanf("%d", &lines);
char (*string)[NUM OF LETTERS]
string = malloc(sizeof(*string) * lines);
char **ptop;
int iStud;
int i;
printf("Enter No. of Students: ");
scanf("%d",&iStud);
ptop=(char **) malloc(sizeof(char)*iStud);
flushall();
for(i=0;i<iStud;i++)
{
ptop[i]=(char *) malloc(sizeof(char)*50);
gets(ptop[i]);
}
for(i=0;i<iStud;i++)
{
puts(ptop[i]);
}
free(ptop);

Trouble with using calloc with an array and returning a pointer

As a reference this is the second part of my assignment:
int* generateFibonacci(int size);
This function will take as input an integer called size. The value contained in the size variable
will represent how many numbers in the Fibonacci sequence to put into the array. The function
will use calloc to create the array of this size and then fill the array with size numbers from the
Fibonacci sequence, starting with 1 and 1. When the array is complete the function will return a
pointer to it.
My trouble come in play when I get the error in line 8 "warning: assignment makes and integer from pointer without a cast".
Another error I get is in line 19 "warning: return makes pointer from integer without a cast".
So my question is, how am I suppose to set up calloc to make the array with a size from a user, then return a pointer to it?
#include <stdio.h>
#include <stdlib.h>
int* generateFibonacci(int size)
{
int i, array[size];
array[size]=(int*)calloc(size, sizeof(int));
array[0]=0;
array[1]=1;
for(i = 2; i < size+1; i++)
array[i] = array[i-2] + array[i-1];
return *array;
}
void printHistogram (int array[], int size)
{
int i, j;
for(i=0; i <= size; ++i)
{
for(j=0; j < array[i]; j++)
{
printf("*");
}
printf("\n");
}
}
int main(void)
{
int array[100], size;
printf("how big will your Fibionacci number be? ");
scanf("%i", &size);
generateFibonacci(size);
printHistogram(array, size);
return 0;
}
how am I suppose to set up calloc to make the array with a size from a user, then return a pointer to it?
For a 1D array of int * Use printf() and scanf()
int *array = {0}; //Note, leaving this initialization method for posterity
//(See related comments below.)
//however agreeing with commentator that the more idiomatic
//way to initialize would be: int *array = NULL;
size_t size = 0;
printf("Enter order of array");
scanf("%d", &size);
array = malloc(size);//create memory with space for "size" elements
if(array){//do other stuff}
But it is unclear from your example, and the comment if you really intend using a 2D array....
As stated in the comments, You have created an int array, then attempted to create memory for it.
int i, array[size];
...
array[size]=(int*)calloc(size, sizeof(int));//wrong
As it is created, array does not need memory. Memory is created on the stack as automatic.
If you wanted a 2D array of int. Then you could do it like this:
int *array[size]; //create a pointer to int []
With this, you can create an array of arrays (in concept) in this way:
for(i=0;i<size;i++) array[i]= calloc(size, sizeof(int));//do not cast the output, not necessary
Now, you essentially have a size x size 2D array of int. It can be assigned values in this manner:
for(i=0;i<size;i++)
for(j=0;j<size;j++)
array[i][j]=i*j;//or some more useful assignment
By the way, adjust the parameters of the calloc() statement as needed, but note, casting its output is not necessary.
Regarding the return statement, your function is prototyped to return a int *.
int* generateFibonacci(int size){...} //requires a return of int *
If you decide to use a 1D array, i.e. int *array={0} (requiring that you allocate memory), then return:
return array;//array is already a `int *`, just return it.
If you are using the 2D array, then to return a int *, you must decide which of the size elements of the array you want to return:
return array[i];//where `i` can be any index value, from 0 to size-1

Resources