how to scanf unknown amount of integer numbers into array in C? - c

I know that I can scanf certain amount of numbers with scanf for example for 3 numbers
scanf("%d %d %d",array[0],array[1],array[2]);
but how can I scan it if I didn't know how many numbers (integer, not float) I would input into an array before enter (NOT EOF)? for example
input : 12 43 23(enter) --> array[0]=12, array[1]=43, array[2]=23
input : 10 20 30 40 50(enter) --> array[0]=10, array[1]=20, array[2]=30, array[3]=40, array[4]= 50
etc..
It's about how to input the numbers into an integer array.
And if it's possible, I want to save it into an 2 dimensions array, for example
input : 12 43 23(enter) --> array[0][0]=12, array[0][1]=43, array[0][2]=23
input : 10 20 30 40 50(enter) --> array[1][0]=10, array[1][1]=20, array[1][2]=30, array[1][3]=40, array[1][4]= 50

Here is come code showing how to scan the integers into a 2D array:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INITSIZE 5
#define BUFFSIZE 1000
void print_and_free(int **array, int rowsize, int colsize);
void check_ptr(void *ptr, const char *msg);
int
main(void) {
int **array;
size_t rowsize = INITSIZE, colsize = INITSIZE;
int row = 0, col, numdigits;
char buffer[BUFFSIZE];
char *number;
array = malloc(rowsize * sizeof(*array));
check_ptr(array, "Allocation");
printf("Enter digits(Enter blank line to end):\n");
while (fgets(buffer, BUFFSIZE, stdin) != NULL && strlen(buffer) != 1) {
col = 0;
numdigits = 0;
if (rowsize == row) {
rowsize *= 2;
array = realloc(array, rowsize * sizeof(*array));
check_ptr(array, "Reallocation");
}
array[row] = malloc(colsize *sizeof(int));
check_ptr(array[row], "Allocation");
number = strtok(buffer, " ");
while (number != NULL) {
numdigits++;
if (colsize == numdigits) {
colsize *= 2;
array[row] = realloc(array[row], colsize * sizeof(int));
check_ptr(array[row], "Reallocation");
}
array[row][col] = atoi(number);
col++;
number = strtok(NULL, " ");
}
row++;
}
print_and_free(array, row, col);
return 0;
}
void
print_and_free(int **array, int rowsize, int colsize) {
int row, col;
printf("Your numbers:\n");
for (row = 0; row < rowsize; row++) {
for (col = 0; col < colsize; col++) {
printf("array[%d][%d] = %d", row, col, array[row][col]);
if (col != colsize - 1) {
printf(", ");
}
}
free(array[row]);
array[row] = NULL;
printf("\n");
}
free(array);
}
void
check_ptr(void *ptr, const char *msg) {
if (!ptr) {
printf("Unexpected null pointer: %s\n", msg);
exit(EXIT_FAILURE);
}
}

Here's how you can store things in a (dynamically allocated) array. This does assume that the line length is limited to 1000 chars though. (Code adapted from How do I use scanf() to take an arbitrary amount of integers?)
#include <stdio.h>
#include <stdlib.h>
int main() {
int val_size = 2;
int* vals = (int*)malloc(val_size * sizeof(int)); // initial array size
char buffer[1000]; // for reading in the line
int pos, bytes_read, num;
int num_read = 0;
if (fgets(buffer, sizeof(buffer), stdin) != 0) {
for (pos = 0; sscanf(buffer+pos, "%d%n", &num, &bytes_read) != EOF; pos += bytes_read) {
// resize the array if needed
if (num_read >= val_size) {
val_size *= 2;
vals = (int*)realloc(vals, val_size * sizeof(int));
}
// store the value in the array
vals[num_read] = num;
num_read++;
}
}
// print the values to prove it works
for (int i = 0; i < num_read; i++) {
printf("%d ", vals[i]);
}
printf("\n");
free(vals); // important after you're done with it
}
You can wrap a while around the if to get multiple lines.

You may use a while loop and check for the return value of scanf. For example:
int num = 0;
int idx = 0;
int arr[100] = { 0 };
while( scanf( "%d", &num ) == 1 )
{
arr[idx++] = num;
if( idx == 99 ) // protect from array overflow
{
break;
}
}
for( int i = 0; i < idx; i++ )
{
printf( "%d\n", arr[i] );
}

Related

How do i create a "matrix" with words in C

The problem is the following:
Have to check if the words in the matrix are palindromes or not. Have to read the words as well.
My main problem is introducing the words because until now I could only do a function reading the first letter, not the whole word.
After that, I think that I can check alone if it is a palindrome or not.
This is an example of data:
mat←["ac" "lup" ]
["ou" "lupul"]
["ABBA" "greu" ]
m←3 number of rows
n←2 number of columns
This what I wrote until now:
A function where you introduce the words:
char** read(int *m ,int *n)
{
printf("No of lines=");
scanf("%d",m);
printf("No of columns=");
scanf("%d",n);
char **a=(char**)malloc(*m*sizeof(char*));
for (int i=0;i<*m;i++)
{
a[i]=(char*)malloc(*n*sizeof(char));
for (int j=0; j<*n; j++)
{
fflush(stdin);
printf("Element [%d][%d]=",i,j);
gets(a[i]+j); // <=> &a[i][j]
}
}
return a;
}
Another one which displays it:
void display(char **x, int m, int n)
{
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
printf("%c ",x[i][j]);
printf("\n");
}
}
Another one which deletes the data:
void freematrix(char **x, int m)
{
for (int i=0; i<m; i++)
free(x[i]);
free(x);
}
This is the main part:
int main()
{
int m, n;
char **mat;
mat=read(&m,&n);
display(mat,m,n);
freematrix(mat,m);
return 0;
}
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ROWS 8 // to limit the usecase
#define MAX_COLS 8
#define MAX_MAT_STR_LEN 15 //
char* str_dupe (const char* str, const int max_slen)
{
if (!str || max_slen < 1) return NULL;
char* dupe = malloc (max_slen + 1);
if (!dupe) {
perror("\nERROR: str_dupe-malloc");
return NULL;
}
dupe[max_slen] = '\0'; // guard
for (int ci =0; ci < max_slen; ++ci) {
dupe[ci] = str[ci];
if ('\0' == dupe[ci])
break; // stop copying
}
return dupe;
}
void free_strMatrix (char ***sm, const int rows, const int cols)
{
if (!sm || rows < 1 || cols < 1) return;
for (int ri = 0; ri < rows; ++ri) {
if (sm[ri]) {
for (int ci = 0; ci < cols; ++ci) {
if (sm[ri][ci]) { // check if it's NULL
free (sm[ri][ci]);
sm[ri][ci] = NULL; //prevent dangling pointers
}
}
free (sm[ri]); // row of string pointers
sm[ri] = NULL; // good practice
}
}
free (sm);
}
char*** read_strMatrix (int *rows, int *cols)
{
while (1) {
printf ("\nChoose Rows [1..%d]: ", MAX_ROWS);
if (1 == scanf("%d", rows) && *rows > 0 && *rows <= MAX_ROWS)
break;
else
printf ("\nERROR: Invalid Row-Count. Try Again!");
}
while (1) {
printf ("\nChoose Columns [1..%d]: ", MAX_COLS);
if (1 == scanf("%d", cols) && *cols > 0 && *cols <= MAX_COLS)
break;
else
printf ("\nERROR: Invalid Column-Count. Try Again!");
}
char*** sm = (char***) calloc ((*rows), sizeof (char**));
if (NULL == sm) {
perror("read_strMatrix-malloc-1");
return NULL;
}
for (int ri = 0; ri < *rows; ++ri) {
sm[ri] = (char**) calloc ((*cols), sizeof (char*));
if (NULL == sm[ri]) {
perror ("read_strMatrix-malloc-2");
//ideally you should free allocated memory before return
free_strMatrix(sm, *rows, *cols);
return NULL;
}
}
char str[256]; //interim string buffer;
for (int ri = 0; ri < *rows; ++ri) {
for (int ci=0; ci < *cols; ++ci ) {
printf ("String for strMatrix[%d][%d] : ", ri, ci);
// strings more than 255 chars will be split ; so be within limit duing input
while (1 != scanf ("%255s", str));
// only copying MAX_MAT_STR_LEN chars
sm[ri][ci] = str_dupe (str, MAX_MAT_STR_LEN);
if (NULL == sm[ri][ci]) {
perror("read_strMatrix-strndup");
//ideally you should free allocated memory before return
free_strMatrix (sm, *rows, *cols);
return NULL;
}
}
printf ("\n");
}
return sm;
}
void disp_strMatrix (char ***sm, const int rows, const int cols)
{
if (!sm || rows < 1 || cols < 1) return;
printf ("\nStringMatrix [%d][%d]:\n", rows, cols);
for (int ri = 0; ri < rows; ++ri) {
if (sm[ri]) {
for (int ci = 0; ci < cols; ++ci)
printf ("%s\t", sm[ri][ci]);
}
printf ("\n");
}
printf ("\n");
}
int main()
{
int rows, cols;
char ***strMatrix;
strMatrix = read_strMatrix (&rows, &cols);
if (!strMatrix) {
printf ("\nERROR: reading strMatrix\n");
return 1;
}
disp_strMatrix (strMatrix, rows, cols);
free_strMatrix (strMatrix, rows, cols);
strMatrix = NULL; // good practice
return 0;
}
You can also prepare an input.txt file like:
3 4
aaaaa sssss ffg gggg
hhhh jj kkkkkk lllll
qqq wwwww eeeee rrrrr
On Linux you can run the program like:
./a.out < input.txt

How to print empty value for element without an integer value in C

So far I have the program does what it needs to do. My issue now is that I have two arrays and when I print them I get 0s for empty elements. I want the empty elements to print nothing.
Example:
Array 1:
1 1
Array 2:
3 3 3 3
Output:
1 3 1 3 0 3 0 3
My goal is:
1 3 1 3 3 3
which is to remove the 0s if I didnt input 0 in array
My code:
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void) {
char * line = NULL;
size_t len = 0;
char * line2 = NULL;
size_t len2 = 0;
char ch;
int counter = 0;
char ch2;
int counter2 = 0;
int mSize;
int mergedArray[20];
int i = 0; // for loop
int j = 0;
int * myPtr;
myPtr = (int * ) malloc(counter * sizeof(int));
int * myPtr2;
myPtr2 = (int * ) malloc(counter2 * sizeof(int));
while (getline( & line, & len, stdin) != EOF) {
//===============
//value 1 for line 1
ch = * line;
printf("line 1: Test: %s\n", line);
char * start = line;
char * eon;
long value;
//===============
//value 2 line 2
getline( & line2, & len2, stdin);
ch2 = * line2;
printf("line 2: Test: %s\n", line2);
char * start2 = line2;
char * eon2;
long value2;
//==============
errno = 0;
//============loop for line 1 =================
printf("=============\n");
printf("Line 1\n");
while ((value = strtol(start, & eon, 0)),
eon != start &&
!((errno == EINVAL && value == 0) ||
(errno == ERANGE && (value == LONG_MIN || value == LONG_MAX))))
{
//getting the size of the line
counter++;
start = eon;
errno = 0;
myPtr[counter] = value;
// printf("Array #1 [%d] %d\n",counter , myPtr[counter]);
} //end of while
printf("Size: %d\n", counter);
printf("=============\n");
//============loop for line 2 =================
printf("Line 2\n");
while ((value2 = strtol(start2, & eon2, 0)),
eon2 != start2 &&
!((errno == EINVAL && value2 == 0) ||
(errno == ERANGE && (value2 == LONG_MIN || value2 == LONG_MAX))))
{
//getting the size of the line
counter2++;
start2 = eon2;
errno = 0;
myPtr2[counter2] = value2;
//printf("Array #2 [%d] %d\n",counter2 , myPtr2[counter2]);
} //end of while
printf("Size: %d\n", counter2);
printf("=============\n");
for (i = 0; i < counter; i++) {
mergedArray[i] = myPtr[i + 1]; // not used
}
mSize = counter + counter2;
for (i = 0, j = counter; j < mSize && i < counter2; i++, j++) {
mergedArray[j] = myPtr2[i + 1]; // not used
//here I print out both arrays
printf("%d %d ", myPtr[i + 1], myPtr2[i + 1]);
}
} // end of main while
return 0;
}
Your program is extremelly complicated. It is a good practice to separate login into functions. In the solution below you need to provide large enouth array for the destination array and both arrays to be merged.
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define SA(a) (sizeof(a)/sizeof((a)[0]))
size_t mergeArrays(int *dest, const int *src1, const int *src2, size_t size_1, size_t size_2)
{
size_t pos = 0;
for(size_t index = 0; index < MAX(size_1, size_2); index++)
{
if(index < size_1) dest[pos++] = src1[index];
if(index < size_2) dest[pos++] = src2[index];
}
return pos;
}
int main(void)
{
int arr1[] = {1,1};
int arr2[] = {3,3,3,3,3};
int dest[SA(arr1) + SA(arr2)];
size_t destsize = mergeArrays(dest, arr1, arr2, SA(arr1), SA(arr2));
for(size_t index = 0; index < destsize; index++)
{
printf("%d ", dest[index]);
}
printf("\n");
}
https://godbolt.org/z/WG4v6T
Here you have the version reading from user and using dynamic memory allocation:
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define SA(a) (sizeof(a)/sizeof((a)[0]))
size_t mergeArrays(int *dest, const int *src1, const int *src2, size_t size_1, size_t size_2)
{
size_t pos = 0;
for(size_t index = 0; index < MAX(size_1, size_2); index++)
{
if(index < size_1) dest[pos++] = src1[index];
if(index < size_2) dest[pos++] = src2[index];
}
return pos;
}
int *readArray(size_t *size)
{
int *arr = NULL;
printf("Enter size:");
if(scanf(" %zu", size) != 1) goto func_return;
arr = malloc(*size * sizeof(*arr));
if(!arr) { free(arr); arr = NULL; goto func_return;}
for(size_t index = 0; index < *size; index++)
{
if(scanf(" %d", &arr[index]) != 1) {free(arr); arr = NULL; goto func_return;}
}
func_return:
return arr;
}
int main(void)
{
size_t size1, size2;
int *arr1 = readArray(&size1);
int *arr2 = readArray(&size2);
int *dest = NULL;
if(arr1 && arr2) dest = malloc(size1 + size2);
if(dest)
{
size_t destsize = mergeArrays(dest, arr1, arr2, size1, size2);
for(size_t index = 0; index < destsize; index++)
{
printf("%d ", dest[index]);
}
}
printf("\n");
free(arr1);
free(arr2);
free(dest);
}
https://godbolt.org/z/5sMbYj

Is my usage of fgets() and strtok() incorrect for parsing a multi-line input?

I'm writing an implementation of the Moore Voting algorithm for finding the majority element (i.e. the element which occurs more than size/2 times) in an array. The code should return the majority element if it exists or else it should return -1. Now my version of the majorityElement(int size, int arr[]) seems to work perfectly fine if I directly hardcode the integer array in the main() function and invoke it from there.
int majorityElement(int size, int arr[])
{
int majorityindex = 0;
int votes = 1;
int index;
for (index = 1; index < size; index++)
{
if (arr[index] == arr[majorityindex])
votes++;
else
votes--;
if (votes == 0)
{
majorityindex = index;
votes = 1;
}
}
int count = 0;
int i;
for (i = 0; i < size; i++)
{
if(arr[majorityindex] == arr[i])
count++;
}
if (count > (size/2))
return arr[majorityindex];
return -1;
}
However, I'm facing some issues if I try to read an input stream like these:
2
5
3 1 3 3 2
3
1 2 3
The first line of the input contains the number of test cases. The first line of the test case will be the size of the array and the second line will be the elements of the array.
I tried to read the input stream from within the main() function like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
int majorityElement(int size, int arr[]);
int main()
{
char buf[3];
fgets(buf, MAX, stdin);
int n = atoi(buf);
char a[3];
char b[MAX];
int i;
int count;
int* num;
for (i = 0; i < n; i++)
{
count = 0;
fgets(a, MAX, stdin);
fgets(b, MAX, stdin);
int x = atoi(a);
char* num[x];
int arr[x];
int k = 0;
char* token = strtok(b, " ");
while (token != NULL)
{
num[k] = token;
arr[k] = atoi(num[k]);
token = strtok(NULL, " ");
k++;
}
printf("%d\n", majorityElement(x, arr));
}
return 1;
}
I took the size of buf[] and a[] as 3 during declaration as they must have sufficient space for the \n character read by fgets() as well as the terminating \0 character. As far as I know, the atoi() function ignores the \n character while converting the character array (string) into an integer. I tried to store the first entry of the input (i.e. the number of entries) in a character array buf, converted it into a string and stored it in a variable n. Similarly, I tried to obtain the size of a test array in a variable x and the test arrays (second line of test case) in an integer array arr. While buf and n seem to obtain the correct values in all cases, I'm not quite sure about arr. I'm aware that fgets() leaves a terminal \n character and that might be causing some havoc during tokenization using strtok, although I can't finger at why. I tried submitting this code on GeeksForGeeks. It gives absolutely correct outputs for the sample test case:
2
5
3 1 3 3 2
3
1 2 3
that is
3
-1
However, when I try to "submit" my solution it says:
Possibly your code doesn't work correctly for multiple test-cases (TCs).
The first test case where your code failed:
Input:
4
1 2 2 1
Its Correct output is:
-1
And Your Code's output is:
1
I can't seem to make sense of this. If I manually write this in stdin:
1
4
1 2 2 1
the code outputs
-1
which is indeed the correct solution. This doesn't match with the output claimed during the submission i.e. 1. So I'm not really sure where I'm going wrong. Have I used fgets() or strtok() incorrectly in the main() function? Or is it something else?
Updated the main() function according to suggestions in the comments.
int main()
{
char buf[MAX];
fgets(buf, MAX, stdin);
int n = atoi(buf);
char a[MAX];
char b[MAX];
int i;
int count;
int* num;
for (i = 0; i < n; i++)
{
count = 0;
fgets(a, MAX, stdin);
fgets(b, sizeof(a), stdin);
a[sizeof(a)-1] = '\0';
b[sizeof(b)-1] = '\0';
int x = atoi(a);
int arr[x];
int k = 0;
char* token = strtok(b, " ");
while (token != NULL)
{
if (k > x)
break;
arr[k] = atoi(token);
token = strtok(NULL, " ");
k++;
}
printf("%d\n", majorityElement(x, arr));
}
return 1;
}
As pointed out by #Vlad, the MAX was set too low in my original array. The question says that the number of entries in an array is upper bounded by 10^7 and each array entry is upper bounded by 10^6 (7 digits). So MAX needs to be of the order 10^8. According to the suggestions in the comments, I'm now using dynamic allocation instead of variable length arrays.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 10000000
int majorityElement(int size, int arr[])
{
int majorityindex = 0;
int votes = 1;
int index;
for (index = 1; index < size; index++)
{
if (arr[index] == arr[majorityindex])
votes++;
else
votes--;
if (votes == 0)
{
majorityindex = index;
votes = 1;
}
}
int count = 0;
int i;
for (i = 0; i < size; i++)
{
if(arr[majorityindex] == arr[i])
count++;
}
if (count > (size/2))
return arr[majorityindex];
return -1;
}
int main()
{
char* buf = calloc (MAX, sizeof(char));
fgets(buf, MAX, stdin);
int n = atoi(buf);
char* a = calloc (MAX, sizeof(char));
char* b = calloc(MAX, sizeof(char));
int i;
for (i = 0; i < n; i++)
{
fgets(a, MAX, stdin);
fgets(b, MAX, stdin);
a[strlen(a)-1] = '\0';
b[strlen(b)-1] = '\0';
int x = atoi(a);
int *arr = calloc(x, sizeof(int));
int k = 0;
char* token = strtok(b, " ");
while (token != NULL)
{
if (k > x)
break;
arr[k] = atoi(token);
token = strtok(NULL, " ");
k++;
}
printf("%d\n", majorityElement(x, arr));
free(arr)
}
free(buf);
free(a);
free(b);
return 1;
}
If I set MAX to 10^7 then the code passes all the test cases and is accepted for submission. However, if I set MAX to 10^8 (as required), I get a segmentation fault. How to overcome this?
Your program has several drawbacks.
For example within the function main there are unused variables declared like
int count;
int* num;
The function does take into account that -1 can be a valid value of the array.
There is a problem with the number of elements that can be specified in a test. It is a very big number (according to the description 1 <= N <= 10000000). So the value of MAX equal to 100 is too low. As a result the data can be read incorrectly and not completely. Also there can occur problems with the variable length arrays.
There is no need to use the function fgets because each integer number can be read using scanf.
I could suggest the following solution. Try it and see whether it will pass the tests.
#include <stdio.h>
#include <stdlib.h>
size_t majorityElement( const int a[], size_t n )
{
size_t majority_index = 0;
for ( size_t i = 1, votes = 1; i < n; i++ )
{
if ( a[majority_index] == a[i] )
{
++votes;
}
else
{
--votes;
}
if ( votes == 0 )
{
majority_index = i;
++votes;
}
}
size_t count = 0;
for ( size_t i = 0; i < n; i++ ) count += a[i] == a[majority_index];
return n / 2 < count ? majority_index : n;
}
int main(void)
{
size_t n = 0;
scanf( "%zu", &n );
for ( size_t i = 0; i < n; i++ )
{
size_t m = 0;
scanf( "%zu", &m );
if ( m != 0 )
{
int *a = calloc( m, sizeof( int ) );
for ( size_t j = 0; j < m; j++ ) scanf( "%d", a + j );
size_t majority_index = majorityElement( a, m );
printf( "%d\n", majority_index == m ? -1 : a[majority_index] );
free( a );
}
}
return 0;
}
If it will not pass the tests then it seems there is a bug in tests.:)
Or if the function return type may not be changed then the function definition can look like
int majorityElement( const int a[], size_t n )
{
size_t majority_index = 0;
for ( size_t i = 1, votes = 1; i < n; i++ )
{
if ( a[majority_index] == a[i] )
{
++votes;
}
else
{
--votes;
}
if ( votes == 0 )
{
majority_index = i;
++votes;
}
}
size_t count = 0;
for ( size_t i = 0; i < n; i++ ) count += a[i] == a[majority_index];
return n / 2 < count ? a[majority_index] : -1;
}

I want to put some strings at dynamic 2D array with pointers(C programming)

Hi I want to get some strings from user then put those in 2D array and
at the end just print every character position in array for test.(Im writing at visual studio 2017)
but I'm getting output like this for example:
marray[1][2]==
marray[1][3]==
marray[1][3]==
and I'm getting this for all cells.
and here is my code so far:
#include <stdio.h>
#include <stdlib.h>
void inputnames(char**, int, int);
void printitems(char**, int, int);
int main(void)
{
int m;
const int n = 30; //students name limit
printf("Enter Number of students:");
scanf_s("%d ", &m); //getting row size from user
//---------------------------------------------
char** p;
p = (char**)malloc(sizeof(char)*m);
for (int i = 0; i < m; i++)
{ //this part for allocating 2d array
p[i] = (char*)malloc(sizeof(char)*n);
}
//--------------------------------------------
inputnames(p, m, n); //filling 2D array
printitems(p, m, n); //print each character with position for test
getchar();
}
void inputnames(char** marray, int mm, int nn)
{
int i = 0, j = 0;
for (i = 0; i<mm; i++)
{
while (marray[i][j] != '\n' && j<nn)
{
scanf_s("%c", &marray[i][j]);
}
}//end of for i
}
void printitems(char** marray, int mm, int nn) //this function is for test
{
int i = 0, j = 0;
for (i = 0; i<mm; i++)
{
for (j = 0; j<nn; j++)
{
printf("marray[%d][%d]=%c\n",i,j,marray[i][j]);
}//end of for j
}//end of for i
}
There are several error in your code.
Don't cast malloc. And your are allocating the incorrect number of bytes
both times. I advice you not to use sizeof(<type>), it's easy to make
mistakes, it's better practice to call malloc like this:
int *arr = malloc(size * sizeof *arr);
Regardless of the type of arr, you would allocate the correct amount of
memory.
You have to check if malloc returns NULL. If it returns NULL you cannot
access the memory.
Also remember that a string must be '\0'-terminated, for a string of length
n, you need n+1 bytes. You either allocate n+1 spaces for the strings, or
in inputnames you should check if j < nn - 1. Also you don't set the
'\0'-terminating byte in inputnames.
The correct allocation is:
char** p;
// calloc initializes the memory to 0,
// great initialization, helps you free the memory faster
// on error
p = calloc(m, sizeof *p);
if(p == NULL)
{
fprintf(stderr, "not enough memory\n");
return 1;
}
for (size_t i = 0; i < m; i++)
{
p[i] = calloc(1, n+1); // size of char is 1
if(p[i] == NULL)
{
fprintf(stderr, "not enough memory\n");
free_strings(p, m);
return 1;
}
}
And you would need the free_strings function:
void free_strings(char **strings, size_t len)
{
if(strings == NULL)
return;
for(size_t i = 0; i < len; ++i)
free(strings[i]);
free(strings);
}
Also your reading is not that efficient, I would use fgets instead:
int inputnames(char** marray, size_t mm, size_t nn)
{
if(marray == NULL || mm == 0 || nn == 0)
return 0;
for(size_t i = 0; i < mm; ++i)
{
printf("Enter text #%d: ", i+1);
fflush(stdout);
if(fgets(marray[i], nn, stdin) == NULL)
{
fprintf(stderr, "cannot read anymore\n");
return 0;
}
// removing the newline
marray[i][strcspn(marray[i], "\n")] = 0;
}
return 1;
}
I forgot to mention this in the answer:
for (i = 0; i<mm; i++)
{
while (marray[i][j] != '\n' && j<nn)
{
scanf_s("%c", &marray[i][j]);
}
}//end of for i
This yields undefined behaviour. You only allocate memory but you don't
initialize it, so you are actually checking if random value if equals to the
newline. You also don't increment j, you are writing always at the same place.
You need to read first, then check second.
for(i = 0; i<mm; i++)
{
do {
if(scanf_s("%c", marray[i] + j) != 1)
{
fprintf(stderr, "Unable to read from stdin\n");
marray[i][j] = 0;
return;
}
} while(marray[i][j++] != '\n' && j<nn);
marray[i][j-1] = 0; // setting the \0-terminating byte
}
and the printitems should look like this:
void printitems(char** marray, size_t mm)
{
if(marray == NULL || mm == 0 || nn == 0)
return;
for(size_t i = 0; i < mm; ++i)
puts(marray[i]);
}
Also don't forget to free the memory when you don't need it anymore.

Segmentation Fault (core dumped) when allocating memory for 2D array

I'm trying to read specific chars inside a file redirected from stdin into a 2D array, I'm not sure if I'm allocating the memory for the 2D array properly. The first line inside the file is the dimensions of the matrix I'm trying to copy.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "QueueImplementation.c"
int tester(char *s, int cnt)
{
int num1, num2;
if(cnt == 0)
{
sscanf(s, "%d %d", &num1, &num2);
if(num1 < 2 || num1 > 20 || num2 < 2 || num2> 20)
{
printf("Incorrect Matrix Dimensions!");
printf("\n");
}
return num1;
}
}
void allocateMem(char ***cell, int n, int m)
{
*cell=(char**)malloc(n*sizeof(int*));
for(int i=0;i<n;i++)
*cell[i]=(char*)malloc(m*sizeof(int));
}
int main(){
char buffer[200];
int j,max_row,max_col;
int count = 0;
int i = 0;
while (fgets(buffer, sizeof buffer, stdin))
{
if(count == 0)
max_col = tester(buffer, count);
count++;
}
max_row = count - 1;
char** cell;
allocateMem(&cell, max_row, max_col);
while (fgets(buffer, sizeof buffer, stdin))
{
for(j = 0;j<max_col;j++)
{
if(buffer[j] != '\n' && buffer[j] != ' ' && buffer[j] < '0')
cell[i-1][j] = (char) buffer[j];
}
i++;
}
for (i = 0;i<max_row;i++)
{
for (j = 0;j<max_col;j++)
{
printf("%c", cell[i][j]);
}
}
}
Test file that I redirect consists of
12 10
oooooooooooo
ooooooooooo.
oooooooo....
se.......ooo
oooooooo....
Mainly consists of "o" and "." except for a single "s" and "e". The 12 and 10 are the dimensions of the matrix that I am trying to copy, so the expected output should be the matrix consisting the o's and .'s along with a single "s" and "e".
fix like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void tester(char *s, int *cols, int *rows){
int cnt;
cnt = sscanf(s, "%d %d", cols, rows);
if(cnt != 2 || *cols < 2 || *cols > 20 || *rows < 2 || *rows > 20){
printf("Incorrect Matrix Dimensions!\n");
exit(EXIT_FAILURE);//The program can not be continued.
}
}
void allocateMem(char ***cell, int n, int m){
*cell = malloc( n * sizeof(char*));
for(int i = 0; i < n; i++)
(*cell)[i] = malloc(m * sizeof(char));
}
int main(void){
char buffer[200] = "";
char **cell;
int max_row, max_col;
int i, j;
fgets(buffer, sizeof buffer, stdin);//read first line
tester(buffer, &max_col, &max_row);//If fgets fails, this also fails
allocateMem(&cell, max_row, max_col);
for(i = 0; i < max_row; ++i){
for(j = 0; j < max_col; j++){
int ch = fgetc(stdin);
if(!isspace(ch))
cell[i][j] = ch;
else
--j;//cancel this turn
}
}
for (i = 0; i < max_row; i++){
for (j = 0; j < max_col; j++){
printf("%c", cell[i][j]);
}
puts("");//put newline
}
//deallocate cell
}

Resources