Allocating memory dynamically to a 2-d array of strings - c

int ReadNames(char ***Names, int *r,int *c)
{
int i, j, k;
char name[100];
printf("Number of Rows: ");
scanf("%d", r);
printf("Number of Columns: ");
scanf("%d", c);
Names=(char ***)malloc(sizeof(char **)*(*r));
for(i=0;i<(*r);i++)
*(Names+i)=(char **)malloc(sizeof(char *)*(*c));
for(i=0;i<(*r);i++)
for(j=0;j<(*c);j++)
{
fflush(stdin);
gets(name);
strcpy(*(*(Names+i)+j),name);
}
return 1;
}
I am trying to allocate the memory to a 2-D array of strings. Later on i want to sort them row wise and column wise, but while allocating the memory , the program is not responding. Is there something i am doing in my code.
in main function readname is called as
ReadNames(&p,&r,&c)
where r and c are the no. of rows and columns.

You need:
*Names = (char **)malloc(sizeof(char **) * (*r));
and consequential changes.
You're passing a triple-pointer in order to be able to return a double-pointer. What you're doing is losing the information about where to store the double-pointer.
There is some truth to the struck out comment; there is also a miscue. A 2D array of strings means that you have three levels of pointer in the basic data. And you need a fourth level of pointer to pass into the function.
Also, using gets() is a recipe for disaster. Don't ever (as in never, as in never ever) use the the gets() function. Not even in toy programs. It gets you into bad habits. The first Internet worm propagated through a program that used gets() (Google search 'morris internet worm').
On Unix and other POSIX-based systems, using fflush(stdin) leads to undefined behaviour. On Windows, the behaviour is defined by Microsoft. If you're running on Windows, then you're OK; if not, you're not.
And I thought Three-Star Programming was bad!
This probably isn't the way I'd do it, but it is a pretty direct translation of what you wrote into something that works, along with a main() program that tests it and frees all the allocated memory. It assumes strdup() is available; if not, it is trivial to write it.
Sample output:
Number of Rows: 2
Number of Columns: 3
R0C0: Row 1, Column 1.
R0C1: Ambidextrous Armless Individual.
R0C2: Data for the third column of the first row.
R1C0: Row 2, Column 1.
R1C1: Row 2, Column 2.
R1C2: Given that the number of rows is 2 and the number of columns is 3, this should be the last input!
Rows = 2, cols = 3.
[0,0] = <<Row 1, Column 1.>>
[0,1] = <<Ambidextrous Armless Individual.>>
[0,2] = <<Data for the third column of the first row.>>
[1,0] = <<Row 2, Column 1.>>
[1,1] = <<Row 2, Column 2.>>
[1,2] = <<Given that the number of rows is 2 and the number of columns is 3, this should be the last input!>>
Working 4-star code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static void ReadNames(char ****Names, int *rows, int *cols)
{
char name[100];
printf("Number of Rows: ");
scanf("%d", rows);
printf("Number of Columns: ");
scanf("%d", cols);
int c;
while ((c = getchar()) != EOF && c != '\n')
;
*Names = (char ***)malloc(sizeof(char ***)*(*rows));
for (int i = 0; i < (*rows); i++)
(*Names)[i] = (char **)malloc(sizeof(char **)*(*cols));
for (int i = 0; i < (*rows); i++)
{
for (int j = 0; j < (*cols); j++)
{
printf("R%dC%d: ", i, j);
if (fgets(name, sizeof(name), stdin) == 0)
{
fprintf(stderr, "Unexpected EOF\n");
exit(1);
}
name[strlen(name)-1] = '\0'; // Zap newline
(*Names)[i][j] = strdup(name);
}
}
}
int main(void)
{
int rows;
int cols;
char ***data = 0;
ReadNames(&data, &rows, &cols);
printf("Rows = %d, cols = %d.\n", rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
printf("[%d,%d] = <<%s>>\n", i, j, data[i][j]);
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
free(data[i][j]);
free(data[i]);
}
free(data);
return 0;
}
Alternative 3-star code
Using three levels of pointer is bad enough; four is horrid. This code restricts itself to three levels of pointer. I assume C99 compatibility, so variables can be declared when convenient in a function. The changes to work with C89/C90 compilers (which are 14 years retrograde now) are simple enough.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char ***ReadNames(int *r, int *c)
{
int i, j;
char name[100];
printf("Number of Rows: ");
scanf("%d", r);
printf("Number of Columns: ");
scanf("%d", c);
int x;
while ((x = getchar()) != EOF && x != '\n')
;
char ***Names = (char ***)malloc(sizeof(char ***)*(*r));
for (i = 0; i < (*r); i++)
Names[i] = (char **)malloc(sizeof(char **)*(*c));
for (i = 0; i < (*r); i++)
{
for (j = 0; j < (*c); j++)
{
if (fgets(name, sizeof(name), stdin) == 0)
{
fprintf(stderr, "Unexpected EOF\n");
exit(1);
}
name[strlen(name)-1] = '\0';
Names[i][j] = strdup(name);
}
}
return Names;
}
static void PrintNames(char ***Names, int r, int c)
{
int i, j;
for (i = 0; i < r; i++)
{
for (j = 0; j < c; j++)
printf("%s ", Names[i][j]);
printf("\n");
}
}
int main(void)
{
int rows;
int cols;
char ***data = ReadNames(&rows, &cols);
PrintNames(data, rows, cols);
printf("Rows = %d, cols = %d.\n", rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
printf("[%d,%d] = <<%s>>\n", i, j, data[i][j]);
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
free(data[i][j]);
free(data[i]);
}
free(data);
return 0;
}
Example output
Number of Rows: 3
Number of Columns: 4
R1C1
R1C2
R1C3
R1C4-EOR
R2C1
R2C2
R2C3
R2C4-EOR
R3C1
R3C2
R3C3
R3C4-EOR
R1C1 R1C2 R1C3 R1C4-EOR
R2C1 R2C2 R2C3 R2C4-EOR
R3C1 R3C2 R3C3 R3C4-EOR
Rows = 3, cols = 4.
[0,0] = <<R1C1>>
[0,1] = <<R1C2>>
[0,2] = <<R1C3>>
[0,3] = <<R1C4-EOR>>
[1,0] = <<R2C1>>
[1,1] = <<R2C2>>
[1,2] = <<R2C3>>
[1,3] = <<R2C4-EOR>>
[2,0] = <<R3C1>>
[2,1] = <<R3C2>>
[2,2] = <<R3C3>>
[2,3] = <<R3C4-EOR>>
Both programs run clean under valgrind.

So, this is the code working...
*Names=(char **)malloc(sizeof(char **)*(*r));
for(i=0;i<(*r);i++)
*(*Names+i)=(char*)malloc(sizeof(char *)*(*c));
for(i=0;i<(*r);i++)
for(j=0;j<(*c);j++)
{
fflush(stdin);
gets(name);
strcpy((*(*Names+i)+j),name);
}
but while printing those names stored...i have a function provided..
int PrintNames(char **Names, int r, int c)
{
int i,j;
for(i=0;i<r;i++)
{ printf("\n");
for(j=0;j<c;j++)
printf("%s ",*(*(Names+i)+j));
}
return 1;
}
Now this PrintNames is also called through main...as "PrintNames(p, r, c);"....but program stops while printing...What could be wrong?

Related

How to read in string input from the user and allocate it?

So I've been working on this code for a while now and I can't figure out why it's not working. Basically I'm suppose to create a program using functions to read in string input from the user which is the filename for “data.txt”. I need a function to determine the number of rows that are in the file in order to allocate an array of character pointers. Then my program should print out the strings read from the file. Finally the program should free the allocated memory.
This is my non-working code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_WIDTH 144
void getFileName(char* array1);
int getLineCount(FILE* data, int max);
char** createArryOfPtrs(int rows);
int main(void)
{
int max = 0;
int rows;
char array1[MAX_WIDTH];
FILE* data = fopen(array1, "r");
getFileName(array1);
getLineCount(data, max);
createArryOfPtrs(rows);
fclose(data);
return 0;
}
void getFileName(char* array1)
{
printf("Enter filename: ");
fscanf(stdin, "%144[^\t]", array1);
}
int getLineCount(FILE* data, int max)
{
int i = 4;
char *array1[MAX_WIDTH];
if(data != NULL)
{
while(fgets(*array1, MAX_WIDTH, data) != NULL)
{
i+=1;
}
}
return i;
}
char** createArryOfPtrs(int rows)
{
int r = 4, c = 9, i, j, count;
char *array1[r];
for(i =0; i < r; i++)
{
array1[i] = (char*)malloc(c * sizeof(char));
}
count = 0;
for(i = 0; i < r; i++)
{
for(j = 0; j < c; j++)
{
array1[i][j] = ++count;
}
}
for(i = 0; i < r; i++)
{
for(j = 0; j < c; j++)
{
printf("%c", array1[i][j]);
}
}
return 0;
}
This is the text file.
larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane
I'm still new to C so I'm very confused. Appreciate any help I can get.
Order matters! You get the name of the file to open after you call fopen. That means the data in array1 will be uninitialized and indeterminate (and seem random).
You need to read the name of the file first.
This issue should have been very clear if you did a little rubber duck debugging.

Allocating dynamic memory using malloc in C

I'm new to C and have been trying to tackle this question. It's a continuation of the last thread I made. I made some progress but still have so much to learn and fix.
In short:
In this question a "vector" is a one dimensional array of integers. Therefore an array of vectors would be a two dimensional array that holds one dimensional arrays inside him.
I need to use these variables:
int** vectors- the 2D array
int size -an integer that represents how many vectors exist inside **vectors
int* sizes-a 1D array of integers that represents the length of the vectors
I need to write the following functions:
int init(int ***vectors, int **sizes, int size)
the function allocated memory to **vectors and *sizes with size and initializes vectors to be full of NULLs,and sizes to be full of zeros.
int set(int **vectors, int *sizes, int index, int *tmp, int tmp_size)
the function receives an array of nulls (**vectors)), frees the vector inside **vectors whose index is index and allocates memory for a new vector, whose length is tmp_size and places inside it *tmp's elements.
This is my code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int init(int*** vectors, int** sizes, int size)
{
int i, k,j;
*sizes = (int*)malloc(size * sizeof(int));
if (*sizes == NULL)
return 0;
for (j = 0; j < size; j++)
{
(*sizes)[j] = 0;
}
*vectors = (int**)malloc(size * sizeof(int*));
if (*vectors == NULL)
return 0;
for (i = 0; i < size; i++)
{
(vectors)[i] = NULL;
}
return 1;
}
int set(int **vectors, int *sizes, int index, int *tmp, int tmp_size)
{
if ((vectors)[index] != NULL)
{
free((vectors)[index]);
}
(vectors)[index] = (int*)malloc(tmp_size * sizeof(int));
if ((vectors)[index] == NULL)
return 0;
for (int b = 0; b < tmp_size; b++)
{
(vectors)[index][b] = tmp[b];
}
sizes[index] = tmp_size;
return 1;
}
int main()
{
int size, i, length, indexhere;
int** vectors = NULL;
int* sizes = NULL;
int* tmp = NULL;
int* p = &vectors;
int tempindex;
printf("\nPlease enter an amount of vectors:\n");
scanf("%d", &size);
init(p, &sizes, size);
printf("Enter index\n");
scanf("%d", &indexhere);
printf("Enter Length\n");
scanf("%d", &length);
tmp = (int*)malloc(length * sizeof(int));
printf("Enter elements:\n");
for (int g = 0; g < length; g++)
scanf("%d", &tmp[g]);
set(&vectors, sizes, indexhere, tmp, length);
system("pause");
return 0;
}
Could someone explain please why the program always crashes?
In init function (vectors)[i] = NULL; should actually be (*vectors)[i] = NULL;
When calling set function from main you should pass vectors instead of &vectors.
There also seems to be several pointer type mismatches in your code, so you should really pay attention to compiler's warnings. This is because C unfortunately allows implicit conversions between incompatible pointers, unlike C++ for example.
You call set like this
set(&vectors, sizes, indexhere, tmp, length);
but the first argument is declared as an int **. By passing &vector you're passing a pointer to vector, i.e. something of type int ***. This mismatch will lead to undefined behavior and probable crashes.
Here is a complete working example.
#include <stdio.h>
#include <stdlib.h>
void destroyVectors(int **vectors, int size)
{
for (int i = 0; i < size; i++)
{
free(vectors[i]);
}
}
int init(int*** vectors, int** sizes, int size)
{
int i, j;
*sizes = (int*)malloc(size * sizeof(int));
if (*sizes == NULL)
return 0;
for (j = 0; j < size; j++)
{
(*sizes)[j] = 0;
}
*vectors = (int**)malloc(size * sizeof(int*));
if (*vectors == NULL)
return 0;
for (i = 0; i < size; i++)
{
(*vectors)[i] = NULL;
}
return 1;
}
int set(int **vectors, int *sizes, int index, int *tmp, int tmp_size)
{
if ((vectors)[index] != NULL)
{
free((vectors)[index]);
}
(vectors)[index] = (int*)malloc(tmp_size * sizeof(int));
if ((vectors)[index] == NULL)
return 0;
for (int b = 0; b < tmp_size; b++)
{
(vectors)[index][b] = tmp[b];
}
sizes[index] = tmp_size;
return 1;
}
int main()
{
int size = 0, length = 0, indexhere = 0;
int** vectors = NULL;
int* sizes = NULL;
int* tmp = NULL;
printf("\nPlease enter an amount of vectors:\n");
scanf("%d", &size);
init(&vectors, &sizes, size);
printf("Enter index\n");
scanf("%d", &indexhere);
printf("Enter Length\n");
scanf("%d", &length);
tmp = (int*)malloc(length * sizeof(int));
printf("Enter elements:\n");
for (int g = 0; g < length; g++)
scanf("%d", &tmp[g]);
set(vectors, sizes, indexhere, tmp, length);
for(int i = 0; i < length; ++i)
printf("byte: %d\n", vectors[indexhere][i]);
printf("sizes index: %d\n", sizes[indexhere]);
free(tmp);
free(sizes);
destroyVectors(vectors, size);
return 0;
}

2D arrays using arrays of pointers or pointers to pointers in C?

I'm writing a C for which I need to create a 2D array. I've found a solution to my problem using double pointers (pointers to pointers) in the following way:
#include <stdio.h>
#include <stdlib.h>
int d = 3;
#define DIM_MAX 9
void changeArray(int d, int *array[d]);
int main()
{
//alocate array of 'd' colummns and 'd' row using malloc using array of pointers
int **array = malloc(d*sizeof(int *));
for(int count = 0; count < d; count++)
{
array[count] = malloc(d*sizeof(int *));
}
/* Call changeArray function */
changeArray(d, array);
for(int i = 0; i < d; i++)
{
for(int j = 0; j < d; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
for(int count = 0; count < d; count++)
{
free(array[count]);
}
return 0;
}
void changeArray(int n, int *array[d])
{
for(int i =0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
array[i][j] = i*j;
}
}
return;
}
The code above works pretty well (it seems), but I've read in the web that using pointer to pointer is not the correct way to create 2D arrays. So I've come up with the following code, which also works:
#include <stdio.h>
#include <stdlib.h>
#define DIM_MAX 9
int d = 3;
void changeArray(int d, int *array[d]);
int main()
{
//alocate array of 'd' colummns and 'd' row using malloc using array of pointers
int *array[DIM_MAX] = {0};
for(int count = 0; count < d; count++)
{
array[count] = (int *)malloc(d*sizeof(int *));
}
/* Call changeArray function */
changeArray(d, array);
for(int i = 0; i < d; i++)
{
for(int j = 0; j < d; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
for(int count = 0; count < d; count++)
{
free(array[count]);
}
return 0;
}
void changeArray(int n, int *array[d])
{
for(int i =0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
array[i][j] = i*j;
}
}
return;
}
What is the difference in using any of the two ways above to write this code?
[Not an answer, but an alternative approach to achieve the desired result, namely defining a user-defined 2D array.]
Assuming the compiler in use supports VLAs you could do this:
#include <stddef.h> /* for size_t */
void init_a(size_t x, size_t y, int a[x][y]); /* Order matters here!
1st give the dimensions, then the array. */
{
for (size_t i = 0; i < x; ++i)
{
for (size_t j = 0; j < y; ++j)
{
a[i][j] = (int) (i * j); /* or whatever values you need ... */
}
}
}
int main(void)
{
size_t x, y;
/* Read in x and y from where ever ... */
{
int a[x][y]; /* Define array of user specified size. */
init_a(x, y, a); /* "Initialise" the array's elements. */
...
}
}
It is actually pretty simple. All you have to do is this:
int i[][];
You are overthinking it. Same as a normal array, but has two indexes.
Let's say you want to create a "table" of 4 x 4. You will need to malloc space for 4 pointers, first. Each of those index points will contain a pointer which references the location in memory where your [sub] array begins (in this case, let's say the first pointer points to the location in memory where your first of four arrays is). Now this array needs to be malloc for 4 "spaces" (in this case, let's assume of type INT). (so array[0] = the first array) If you wanted to set the values 1, 2, 3, 4 within that array, you'd be specifying array[0][0], array[0][1], array[0][2], array[0][3]. This would then be repeated for the other 3 arrays that create this table.
Hope this helps!

Functions for dynamically allocating an array in C -- Any difference between the two?

Suppose you have a function in C that accepts the dimensions for a 2d array (for simplicity's sake, say for a square nxn array), dynamically allocates the array, then returns it.
I'm aware allocating memory here might be considered somewhat bad practice to begin with, since it will need to be freed elsewhere, but suppose that's not a huge issue. I'm wondering if there's any advantages/disadvantages associated with these two variations of said function:
Variation 1 - Locally define int** variable in function, allocate/return array:
int **create_array(int n) {
// define array pointer, allocate array...
int **a_ = (int**)calloc(n,sizeof(int*));
for (int i = 0; i < n; i++)
a_[i] = (int*)calloc(n,sizeof(int));
return a_;
}
int main() {
int n = 3;
int **array2d = create_array(n)
printf("First element: %d%c",array2d[0][0],'\n');
// do stuff... etc...
}
Variation 2 - Add in-out int** parameter to function, allocate/return array:
int **create_array_2(int **a_, int n) {
// allocate array...
a_ = (int**)calloc(n,sizeof(int*));
for (int i = 0; i < n; i++)
a_[i] = (int*)calloc(n,sizeof(int));
return a_;
}
int main() {
int n = 3;
int **array2d;
array2d = create_array_2(array2d,n);
printf("First element: %d%c",array2d[0][0],'\n');
// do other stuff... etc...
}
Obviously they return the same result and achieve the same task, but is one considered to be safer/more efficient/better practice than the other? In my opinion the 2nd variation just makes things look a bit redundant, but I'm curious if there's any real differences between the two and what happens on the stack/heap when they're called. Hopefully this isn't a dumb question; it's just something I've been curious about. If anyone has insight to share, I'd appreciate it.
I'll probably try to avoid calling malloc and free to many times so this kind of approach is what I'll do:
Example 1:
#include <stdio.h>
#include <stdlib.h>
int *foo(size_t row, size_t col);
int main(void){
int *arr;
unsigned int row, col, k;
printf("Give the ROW: ");
if ( scanf("%u",&row) != 1){
printf("Error, scanf ROW\n");
exit(1);
}
printf("Give the COL: ");
if ( scanf("%u",&col) != 1){
printf("Error, scanf COL\n");
exit(2);
}
arr = foo(row, col);
for (k = 0 ; k < (row * col) ; k++){
printf("%d ",arr[k]);
}
free(arr);
}
int *foo(size_t row, size_t col){
unsigned int i, j;
int *arr = malloc(sizeof *arr * row * col);
int l = 0;
if(arr == NULL){
printf("Error, malloc\n");
exit(3);
}
for ( i = 0; i < row ; i++){
for ( j = 0 ; j < col ; j++){
arr[i * col + j] = l;
l++;
}
}
return arr;
}
Output:
Give the ROW: 6
Give the COL: 3
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Example 2 (if you are working with the standard C):
#include <stdio.h>
#include <stdlib.h>
int (*foo(size_t row, size_t col))[];
int main(void){
size_t row, col;
printf("Give the ROW: ");
if ( scanf("%zu",&row) != 1){
printf("Error, scanf ROW\n");
exit(1);
}
printf("Give the COL: ");
if ( scanf("%zu",&col) != 1){
printf("Error, scanf COL\n");
exit(2);
}
int (*arr)[col] = foo(row, col);
for ( size_t i = 0; i < row; i++){
for( size_t j = 0; j < col; j++){
printf("%d ",*(*(arr+i)+j));
}
}
free(arr);
}
int (*foo(size_t row, size_t col))[]{
int (*arr)[col] = malloc(row * col * sizeof(int));
int l=0;
if (arr == NULL){
printf("Error, malloc\n");
exit(3);
}
for ( size_t i = 0; i < row; i++){
for( size_t j = 0; j < col; j++){
*(*(arr+i)+j) = l;
l++;
}
}
return arr;
}
Output:
Give the ROW: 6
Give the COL: 3
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
The whole point here is that the call of malloc and free in both examples takes place only one time
IMO, of the two you are better off simply returning the value. This way there's a pure and solid wall between you and the caller.
"Give me some stuff!"
"Okay, here's some stuff."
On the other hand, for actually allocating an array of fixed size, why bother with pointers? Why not declare your return type so as to be castable to a sized array?
int (*p2a)[15] = (int(*)[15])create_array_2(15, 15);
Then you would calloc(15*15,sizeof(int)) and be done.

define a two-dimensional global array which its size have to be scanned from a file

I want to define a two dimensional array as a global variable:
int visited[nbVertices][nbVertices];
but the problem that I have to scan the "nbVertices" from a file. is there anyway to fix this problem ?
I think it may be fixed by using pointers, but I don't know how to do it.
So, while we're at it: you don't need the array to be global. Hence, you can just use variable-length arrays and pass the array to all the functions that need it:
void printArray(int n, int k, int arr[n][k])
{
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
printf("%6d", arr[i][j]);
}
printf("\n");
}
}
int main()
{
// get user input in the format "n" <space> "k"
char *end;
char buf[LINE_MAX];
if (!fgets(buf, sizeof buf, stdin))
return -1;
// create array, fill it with random stuff
int n = strtol(buf, &end, 10);
int k = strtol(end, NULL, 10);
int a[n][k];
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
a[i][j] = random();
}
}
// print it
printArray(n, k, a);
return 0;
}
Use malloc.
Your code might look something like this:
// somewhere in file, global
int **visited;
// somewhere in your code, when you read nbVertices
visited = malloc(sizeof(int*) * nbVertices);
for(size_t i = 0; i < nbVertices; i++)
visited[i] = malloc(sizeof(int) * nbVertices);
there shouldn't be any major differences using visited

Resources