Segmentation fault when trying to read a file with 4000^2 characters - arrays

I'm writing a program to read numbers from a .txt file to then put into a 2-dimensional matrix that I can use to do matrix multiplication with but at this point I'm having alot of trouble getting the portion of my code that scans the file to work properly. I have two randomly generated matrixes that I'm using and for the smaller one it will read the first 400 values but then the rest of the array will be zeros. For the larger one, which is 4000x4000, it will just throw a segmentation fault without even going into the main. Any ideas at what would be causing this? I change ARRAY_SIZE to whatever the array length and Width are.
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE 4000
int main(int argc, char *argv[]) {
// Form to read: ./programname #ofthreads inputfilename1 inputefilename2 outputfilename
if(argc != 5) {
printf("Error! usage: ./programname #ofthreads inputfilename1 inputfilename2 outputfilename");
return (EXIT_FAILURE);
}
// get number of threads
int numThreads = atoi(argv[1]);
// make file pointers
FILE *fp1;
FILE *fp2;
// assign pointer to file name
fp1 = fopen(argv[2], "r");
fp2 = fopen(argv[3], "r");
// Error Handling if file doesn't exist
if (fp1 == NULL) {
printf("Error: File 1 does not exist. ");
return (EXIT_FAILURE);
}
if (fp2 == NULL) {
printf("Error: File 2 does not exist. ");
return (EXIT_FAILURE);
}
// initialize arrays
int array1[ARRAY_SIZE][ARRAY_SIZE] = {0};
int array2[ARRAY_SIZE][ARRAY_SIZE] = {0};
// initialize dimension ints
int size1[2];
int size2[2];
// Get Dimensions
fscanf(fp1,"%d ",&size1[0]);
fscanf(fp1,"%d \n", &size1[1]);
fscanf(fp2,"%d ",&size2[0]);
fscanf(fp2,"%d \n", &size2[1]);
int length1 = size1[0];
int width1 = size1[1];
int length2 = size2[0];
int width2 = size2[1];
for(int n = 0; n < length1; n++){
for(int m = 0; m < width1; m++){
fscanf(fp1, "%d ", &array1[m][n]);
}
}
for(int n = 0; n < length2; n++){
for(int m = 0; m < width2; m++){
fscanf(fp1, "%d ", &array2[m][n]);
}
}
// Process file here
// Close file
fclose(fp1);
fclose(fp2);
for(int n = 0; n < width1; n++){
for(int m = 0; m < length1; m++){
// printf("%d ", array1[m][n]);
}
printf("\n");
}
printf("Number of threads = %d\n", numThreads);
printf("Size1 = %d x %d\n", size1[0],size1[1]);
printf("Size2 = %d x %d\n", size2[0],size2[1]);
return 0;
}

2 x 4000 x 4000 ints will most probably take up more stack space than you have available. Allocate the memory dynamically using calloc instead (declared in stdlib.h):
// allocate space for ARRAY_SIZE elements of size int[ARRAY_SIZE] and zero the memory:
int(*array1)[ARRAY_SIZE] = calloc(ARRAY_SIZE, sizeof *array1);
int(*array2)[ARRAY_SIZE] = calloc(ARRAY_SIZE, sizeof *array2);
if(array1 == NULL || array2 == NULL) exit(1);
However, by the looks of it, you don't actually need all that memory in most cases since you get length1, width1, length2 and width2 from the files. Allocate the arrays after you've gotten that input from the files:
if(fscanf(fp1, " %d %d", &length1, &width1) != 2 ||
fscanf(fp2, " %d %d", &length2, &width2) != 2) exit(1);
int(*array1)[width1] = calloc(length1, sizeof *array1);
int(*array2)[width2] = calloc(length2, sizeof *array2);
if(array1 == NULL || array2 == NULL) exit(1);
Then use array1 and array2 just like you did before.
When you are done with them, free the allocated memory:
free(array1);
free(array2);

Process stack size is limited (few MiBs). It varies between systems based on OS implementation. If you need anything over that, better get it from heap (Memory management calls).
int rows = 4000;
int cols = 4000;
int **array = (int**) malloc (rows * sizeof(int*));
if (!array) {
perror("malloc1");
exit(1);
}
for (ri = 0; ri < rows; ++ri) {
array[ri] = (int*) malloc (cols * sizeof(int));
if (!array[ri]) {
perror("malloc2");
exit(2);
}
}
Remember to free the allocated memory in reverse order. First the columns' (loop) then the rows'.
Edit:
3. Assuming you allocated both array1 & array2 using malloc() calls.
Reading array2 contents
fscanf(fp1, "%d ", &array2[m][n]);
shouldn't that be fp2?
Since you're going to do matrix multiplication you need to verify the order of matrices.
first write code for smaller matrix dimensions without malloc() & without reading data from files.

Related

Array elements are "lost" outside the function

I have a matrix in a file like:
3
1 2 3
4 5 6
7 8 -9
where the first line indicates the square matrix order. I'm using the following code to read the file and store it into a vector (I have removed all if checks for sake of simplicity):
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int read_matrix_file(const char *fname, double *vector)
{
/* Try to open file */
FILE *fd = fopen(fname, "r");
char line[BUFSIZ];
fgets(line, sizeof line, fd);
int n;
sscanf(line, "%d", &n)
vector = realloc(vector, n * n * sizeof *vector);
memset(vector, 0, n * n * sizeof *vector);
/* Reads the elements */
int b;
for(int i=0; i < n; i++) {
// Read the i-th line into line
if (fgets(line, sizeof line, fd) == NULL) {
perror("fgets");
return(-1);
}
/* Reads th j-th element of i-th line into the vector */
char *elem_ptr = line;
for (int j=0; j < n; j++) {
if(sscanf(elem_ptr, "%lf%n", &vector[n*i+j] , &b) != 1) {
perror("sscanf");
return(1);
}
elem_ptr += b;
}
}
fclose(fd);
/* HERE PRINTS OK */
for(int i=0; i<n*n; i++)
printf("%i %f\n",i, vector[i]);
return n;
}
The read_matrix_file receives a filename and an array of doubles and fill the array, returning the matrix order. The expected usage can be seen in this code block.
int main(void)
{
const char *fname = "matrix.txt";
double *vector = malloc(sizeof * vector);
int n = read_matrix_file(fname, vector);
/* Here prints junk */
for(int i=0; i<n*n; i++)
printf("%i %f\n",i, vector[i]);
free(vector);
}
The issue is, the printf works fine inside the read_matrix_file but seems invalid in main.
I'm allocating the array outside the function and passing it by "reference", but I'm very suspecious of realloc, unfortunatelly I don't know how to fix or a better approach.
You are reallocating memory inside read_matrix_file() and storing the elements of the matrix in that memory region. But when you come out of the function, since the pointer vectoris a local variable, its new value is lost when you leave the function.
When you come back inside main() vector still points to the (now likely invalid) memory region that you had previously allocated with malloc().
You should either allocate large enough memory before calling read_matrix_file or pass a double pointer (**) if you want to modify the pointer and see the change reflected back in main()
What I meant is something like this:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int read_matrix_file(const char *fname, double **p_vector)
{
/* Try to open file */
FILE *fd = fopen(fname, "r");
char line[BUFSIZ];
fgets(line, sizeof line, fd);
int n;
sscanf(line, "%d", &n);
*p_vector = realloc(*p_vector, n * n * sizeof **p_vector);
double *vector = *p_vector;
memset(vector, 0, n * n * sizeof *vector);
/* Reads the elements */
int b;
for(int i=0; i < n; i++) {
// Read the i-th line into line
if (fgets(line, sizeof line, fd) == NULL) {
perror("fgets");
return(-1);
}
/* Reads th j-th element of i-th line into the vector */
char *elem_ptr = line;
for (int j=0; j < n; j++) {
if(sscanf(elem_ptr, "%lf%n", &vector[n*i+j] , &b) != 1) {
perror("sscanf");
return(1);
}
elem_ptr += b;
}
}
fclose(fd);
/* HERE PRINTS OK */
for(int i=0; i<n*n; i++)
printf("%i %f\n",i, vector[i]);
return n;
}
In main, call it with:
int n = read_matrix_file(fname, &vector);
EDIT: Please note that this code does not handle the failure of realloc() properly.

2-Dimensional array with malloc, function call to allocate

I'm working on a project and I'm kinda stuck at a problem. I'm trying to read a file that contains a number in the first line that gives the number of rows, and then following the matrix of integers, separated by spaces.
I want to make a pointer in the main, then call the function with the pointer as parameter, the function should read the first number in the txt file, then create a 2d array with malloc, then read the matrix in the textfile and return.
but either i get it so the function can allocate and read the matrix, but then i have something wrong with the pointer when calling the function so i cant use the allocated and read stuff in the main, or im getting errors when trying to call by reference and allocate stuff in the function then.
void readjobs(FILE* fp, int ***array, int linesToRead, int facilityCount) {
int ch = 0;
int rows = 0;
while ((ch = fgetc(fp)) != '\n')
{
rows = ch - 48;
//rows = rows * 10 + (ch - 48);
}
if (rows > linesToRead) rows = linesToRead;
*array = (int**)malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
/* size_y is the height */
*array[i] = (int*)malloc(facilityCount * sizeof(int));
}
int i = 0, j = 0;
while ((ch = fgetc(fp)) != EOF)
{
if (ch == '\n')
{
i++;
printf("\n");
}
else if (ch == ' ')
{
j++;
printf("%i ", *array[i][j]);
}
else //wenn es ne nummer ist
{
*array[i][j] = (*array[i][j] * 10) + (ch - 48);
}
}
}
int main(int argc, char** argv) {
int facilities_count = -1;
int jobs_count = -1;
int **jobs = NULL;
FILE *fp; //Zeiger für Datei
fp = fopen("jobs.txt", "r"); //Dateizugriff, Datei als read
if (fp == NULL) { //falls die Datei nicht geoeffnet werden kann
printf("Datei konnte nicht geoeffnet werden!!\n");
}
else { //Datei konnte geoeffnet werden
printf("Datei ist lesbar\n");
readjobs(fp, &jobs, 6, 6);
if (jobs == NULL)printf("nullpionter");
else {
for (int i = 0; i < 6; i++) {
printf("\n");
for (int j = 0; j < 6; j++) {
printf("%x ", jobs[i][j]);
}
}
}
fclose(fp); //Dateizugriff wieder freigeben
}
MPI_Finalize();
getchar();
return 0;
}
Textfile example:
6
3 2 2 1 5 4
1 1 3 4 2 0
1 2 3 4 5 1
3 4 2 0 1 5
1 0 5 2 3 4
4 0 1 3 5 2
the first number "6" in this case is how many lines, and the rest is the matrix to be read
Your main problem
I compiled your code with debugging on:
$ cc -g mat.c -Wall -Wextra
Ran it in debugger:
$ gdb a.out
(gdb) run
Starting program: /tmp/a.out
Datei ist lesbar
Program received signal SIGSEGV, Segmentation fault.
0x00005555555548ff in readjobs (fp=0x555555756010, array=0x7fffffffe740, linesToRead=6, facilityCount=6)
at mat.c:18
18 *array[i] = (int*)malloc(facilityCount * sizeof(int));
Ok, so it crashes at this line:
*array[i] = (int*)malloc(facilityCount * sizeof(int));
Doing so is always a good idea to find out what the problem is. What could be the cause? Unfortunately it is not trivial in this case. Unless you really understand pointers. *array[i] is not what you want. You want (*array)[i].
Remember that x[i] is just a shortcut for *(x+i). Furthermore, [] has higher priority than *. So *x[i] = *(x[i]) = *(*(x+i)), but what you want is (*x)[i] = *((*x) + i) which clearly is not the same thing.
Other stuff
I would definitely extract the creation of the matrix, like this:
int ** createMatrix(int rows, int columns) {
printf("%d %d\n", rows, columns);
int **ret;
ret = malloc(rows * sizeof *ret);
if(!ret) { perror("Error: "); exit(EXIT_FAILURE); }
for(int i=0; i<columns; i++) {
ret[i] = malloc(columns * sizeof (*ret)[0]);
if(!ret[i]) { perror("Error: "); exit(EXIT_FAILURE); }
}
return ret;
}
and then in your code:
*array = createMatrix(rows, facilityCount);
// Don't trust my code. Check the pointer.
if(!array) { perror("Error: "); exit(EXIT_FAILURE); }
Remember to ALWAYS check if malloc succeeded.
And your way of reading the numbers is very weird. If you are a beginner who came up with this method on your own, that's actually pretty impressive, but it's not a good method. Read about fscanf and getline.

how to search an element from a file in c

My code needs to do three things:
Read numbers from a file FILE1 into an array (dynamic)
Sort those numbers
Search for numbers input from a FILE2 in the sorted array.
.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main (int argc, char *argv[]) {
FILE *fp1 = fopen ("myFile1.txt", "r");
if (fp1 == NULL) {
printf ("cannot open this file");
exit (0);
}
FILE *fp2 = fopen ("test1.txt", "w");
if (fp2 == NULL) {
puts ("Not able to open this file");
exit (1);
}
int i = 0, num, j, k;
int *B = NULL;
int *C;
int a;
int size = 32;
B = malloc (sizeof (int) * size);
while (fscanf (fp1, "%d", &num) == 1) {
if (i < size) {
B[i] = num;
fprintf (fp2, "%d\r\n", num);
i++;
}
else {
C = malloc (sizeof (int) * 2 * size);
memcpy (C, B, size * sizeof (int));
free (B);
B = &C[0];
B[i] = num;
i++;
size = size * 2;
i++;
for (j = 0; j < size; ++j) {
for (k = j + 1; k < size; ++k) {
if (B[j] < B[k]) {
a = &B[j];
B[j] = B[k];
B[k] = a;
}
}
}
printf ("after sorting");
for (j = 0; j < size; ++j)
printf ("%d\n", B[j]);
}
}
return 0;
fclose (fp1); /* note this code is never reached */
fclose (fp2);
}
I successfully complete the first part of reading in the numbers from a file. But I am not able to understand how to sort these numbers.
I am trying to apply bubble sort, but it puts 0s in my array. How is my implementation incorrect?
& is the address-of operator. You pass it as a pointer. You need a = B[i], since a is an int.
Now you sort the numbers descending, if you want them to be ascending change the < to > in if (B[j] < B[k]).
Also you must always check whether malloc succeeded or not with e.g.:
if (!B) {
fprintf(stderr,"B alloc error");
exit(-1);
}
Also you might want to consider realloc.
In addition there is a built-in qsort in stdlib.h, which gives much better time than O(n^2).
Note: I haven't tested your file operations, since you said they work properly.

C - Initialize Global 2d Array based upon File

I would like it create a 2D array based upon values in a file. I am able to do this by making the array local with the following code:
int main()
{
int a = 5; //this is from a file
int b = 6; //this is from a file
int (*array2d)[a] = malloc(sizeof(int)*a*b);
return 0;
}
However, I would like array2d to be global. The following doesn't work:
int **array2d
int main()
{
int a = 5; //this is from a file
int b = 6; //this is from a file
(*array2d)[a] = malloc(sizeof(int)*a*b);
return 0;
}
Is there any simple way to do this?
Allocation and de-allocation of memory for 2D array you can do with functions:
#include <stdlib.h>
#include <stdio.h>
int ** allocIntArray(int nrows, int ncols)
// allocate memory for 2D array and returns pointer if successful or NULL if failed
{
int r, c; // rows and cols counters
int ** parray; // pointer to array
// allocate memory for rows pointers
parray = (int **) malloc(nrows * sizeof(int *));
if( parray == NULL) // check
{
return NULL; // error sign
}
// allocate memory for each row
for (r = 0; r < nrows; r++)
{
parray[r] = (int*) malloc(ncols * sizeof(int));
if( parray[r] == NULL ) // check
{
// clean memory that was allocated before error
while(--r >= 0)
{
free(parray[r]);
}
free(parray);
return NULL; // error sign
}
}
// return when success
return parray;
}
int freeIntArray(int nrows, int **parray)
// frees memory allocated for 2D array and returns 1 if successful or 0 if failed
{
int r; // rows counter
if( parray == NULL || nrows < 1)
{
return 0;
}
// free memory allocated for each row
for (r = 0; r < nrows; r++)
{
if(parray[r] != NULL)
{
free(parray[r]);
}
}
// free memory allocated for rows pointers
free(parray);
return 1;
}
Having this two functions you can create array of any size, e.g.:
int ** globArr;
int nrows; // number of rows
int ncols; // number of columns
int main(int argc, char * argv[])
{
// let's filename is in argv[1]
if( argc < 2) // we have not filename
{
printf("File name must be given as command line argument!\n");
return 1; // exit from program
}
// when we have filename try to use it
FILE * f = fopen(argv[1], "r");
if( f == NULL ) // we cannot read from file
{
printf("File %s cannot be read!\n", argv[1]);
return 2; // exit from program
}
// when we have file openned for reading
// we try to read first two numbers and use them as size of array
if( 2 != fscanf(f, "%d %d", &nrows, &ncols) ) // we cannot read two numbers
{
printf("ERROR: Wrong file format!\n");
return 3; // exit
}
// check that numbers are positive
if( nrows < 1 || ncols < 1 )
{
printf("ERROR: Wrong data size!\n");
return 4; // exit
}
// now we can allocate memory
globArr = allocIntArray(nrows, ncols);
// check that array allocated
if(globArr == NULL)
{
printf("ERROR: Cannot allocate memory!\n");
return 5; // exit
}
// and start a loop to read data from file
int r, c;
for(r = 0; r < nrows; r++)
{
for(c = 0; c < ncols; c++)
{
if (feof(f)) // end of file reached
{
printf("ERROR: Unexpected end of file!\n");
return 6; // exit
}
if( 1 != fscanf(f, "%d", &globArr[r][c]) )
{
printf("ERROR: Wrong file format!\n");
return 6; // exit
}
}
}
fclose(f);
// Now work with data
// . . .
return freeIntArray(nrows, globArr);
}
Note: file format can be different from my. I hope, that program will read files in formats
2 3
10 20 30
40 50 60
or
2 3 10 20 30 40 50 60
or
2
3
10
20
30
40
50
60
where 2 and 3 define size of 2d-array

Getting every other line empty on output

I have a problem with getting every other line empty on output with this code. The desired output is: http://paste.ubuntu.com/1354365/
While I get: http://paste.ubuntu.com/1356669/
Does anyone have an idea of why I'm getting these empty lines on every other line?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *fp;
FILE *fw;
int main(int argc, char *argv[]){
char buffer[100];
char *fileName = malloc(10*sizeof(char));
char **output = calloc(10, sizeof(char*));
char **outputBuffer = calloc(10, sizeof(char*));
fw = fopen("calvin.txt", "w+");
for(int y = 0; y < 6; y++){
for(int i = 0; i < 10; i ++)
{
output[i] = malloc(100);
}
for(int x = 0; x < 12; x++){
sprintf(fileName,"part_%02d-%02d", x, y);
fp = fopen(fileName, "rb");
if(fp == NULL)
{
printf("Kan ikke åpne den filen(finnes ikke/rettigheter)\n");
}
else if(fp != NULL){
memset(buffer, 0, 100);
for(int i = 0; i < 10; i++){
outputBuffer[i] = malloc(100);
}
fread(buffer, 1, 100, fp);
for(int i = 0; i < 100; i++){
if(buffer[i] == '\0')
{
buffer[i] = ' ';
}
else if(buffer[i] == '\n')
{
buffer[i] = ' ';
}
}
for(int i = 0; i < 10; i++) {
strncpy(outputBuffer[i], buffer + i * 10, 10);
strncat(output[i], outputBuffer[i]+1, 11);
}
}
}
for(int i = 0; i < 10; i++){
printf("%s\n", output[i]);
}
}
fclose(fp);
free(fileName);
}
You are not reading correcting from the file. On the first image in the beginning you have:
o ""oo " o o o
on the second
""oo o o o
That does not make a lot of sense because it is the first line. It is not related to empty lines since we are talking about the first line.
It seems that you are reading -2 characters from the left so " prints over o the other " on the ' ' ect..
Try this away, may not be the most efficient solution:
int read(char *file)
{
FILE *fp = NULL;
int size = 0, pos = 0,i;
fp = fopen(file,"r");
if (!fp) return 0;
for(; ((getc(fp))!=EOF); size++); // Count the number of elements in the file
fclose(fp);
char buffer[size];
fp = fopen(file,"r");
if (!fp) return 0;
while((buffer[pos++]=getc(fp))!=EOF); // Saving the chars into the buffer
for(i = 0; i < pos; i++) // print them.
printf("%c",buffer[i]);
fclose(fp);
return 1;
}
This part seems problematic:
strncpy(outputBuffer[i], buffer + i * 10, 10);
strncat(output[i], outputBuffer[i]+1, 11);
1) Why is it necessary to use the extra outputBuffer step?
2) You know that strncpy() isn't guaranteed to null-terminate the string it copies.
3) More significantly, output[i] hasn't been initialized, so strncat() will concatenate the string after whatever junk is already in there. If you use calloc() instead of malloc() when creating each output[i], that might help. It's even possible that your output[i] variables are what hold your extra newline.
4) Even if initialized to an empty string, you could easily overflow output[i], since you're looping 12 times and writing up to 11 characters to it. 11 * 12 + 1 for the null terminator = 133 bytes written to a 100-byte array.
In general, unless this is a class assignment that requires use of malloc(), I don't understand why you aren't just declaring your variables once, at the start of the program and zeroing them out at the start of each loop:
char fileName[10];
char output[10][100];
char outputBuffer[10][100];
And, as stated by others, your allocating a bunch of memory and not trying to free it up. Allocate it once outside of your loop or just skip the allocation step and declare them directly.

Resources