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.
Related
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.
My code for dynamically allocating arrays, even though the Input methods for both arrays pattern and text are same text outputs different values, can anyone solve this issue?
#include<stdio.h>
#include<stdlib.h>
int main() {
int length=5;
int * pattern = malloc(length * sizeof(int));
int * text = malloc(length * sizeof(int));
int pattern_size=0;
int text_size=0;
printf("Enter Pattern:");
char c;
while(c != '$' && scanf("%c",&c) != '\n'){
if(pattern_size >= length)
pattern = realloc(pattern, (length += 10) * sizeof(int));
if(c!=',') pattern[pattern_size] = atoi(&c)+pattern[pattern_size]*10;
else if(c==',') {
pattern_size++;
}
}
printf("\nPlease enter the replacement text:");
// get_array(text,&text_size,length);
char d;
while(d != '$' && scanf("%c",&d) != '\n'){
if(text_size >= length)
text = realloc(text, (length += 10) * sizeof(int));
if(d!=',') text[text_size] = atoi(&d)+text[text_size]*10;
else if(d==',') {
text_size++;
}
}
for(int i=0;i<pattern_size; i++){
printf("%d ",pattern[i]);
}
printf("\n");
for(int i=0;i<text_size; i++){
printf("%d ",text[i]);
}
printf("\n");
return 0;
}
Input
Enter Pattern:1,2,3,4,5,6,7,8,9,0,$
Please enter the replacement text:1,2,3,4,5,6,7,8,9,0,$
OUTPUT
1 2 3 4 5 6 7 8 9 0
1 2 3 4 5 6 10417 8 540155953 540287027
You should ever check the return value of malloc and scanf.
Scanf does not return the element scanned. Please check man 3 scanf
On success, these functions return the number of input items
success‐ fully matched and assigned; this can be fewer than
provided for, or even zero, in the event of an early matching
failure. The value EOF is returned if the end of input is reached
before either the first successful conversion or a matching
failure occurs. EOF is also returned if a read error occurs, in
which case the error indicator for the stream (see ferror(3)) is
set, and errno is set to indicate the error.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
int length = 1;
int *pattern = calloc(length, sizeof(int));
if (pattern == NULL) {
fprintf(stderr, "Unable to find free memory\n");
exit(EXIT_FAILURE);
}
int* text = calloc(length, sizeof(int));
if (text == NULL) {
fprintf(stderr, "Unable to find free memory\n");
exit(EXIT_FAILURE);
}
int pattern_size = 0;
int text_size = 0;
printf("Enter Pattern:\n");
char c = ' ';
while (c != '$') {
if (scanf("%c", &c) != 1) {
fprintf(stderr, "Error in scanf\n");
exit(EXIT_FAILURE);
}
if (isdigit(c) != 0) {
pattern[pattern_size] = c - 48;
pattern_size++;
pattern = realloc(pattern, (pattern_size + 1) * sizeof(int));
}
}
printf("\nPlease enter the replacement text:\n");
// get_array(text,&text_size,length);
char d = ' ';
while (d != '$') {
if (scanf("%c", &d) != 1) {
fprintf(stderr, "Error in scanf\n");
exit(EXIT_FAILURE);
}
if (isdigit(d) != 0) {
text[text_size] = d - 48;
text_size++;
text = realloc(text, (text_size + 1) * sizeof(int));
}
}
fprintf(stdout, "\nOUTPUT:\n");
for (int i = 0; i < pattern_size; i++)
printf("%d ", pattern[i]);
printf("\n");
for (int i = 0; i < text_size; i++)
printf("%d ", text[i]);
printf("\n");
return 0;
free(pattern);
free(text);
}
Including ctype.h you canuse the library function int isdigit(char c) that take in input a char and tells you if it is a number between 0 and 9.
Im tryin to read a ascii-file consisting of 2 columns of and a variable nr of rows. Reading is done by processor 0 and then the data is distributed using MPI_Bcast(...). I had to create a 1-dim buffer array which contains the data and is sent to all other procs because I haven't found a way to directly broadcast the 2-dim. data.
There's something wrong with the allocation of the array arr. When I try to print the data, the first 3 rows are printed and then I get a segmentation fault. Most likely there are several mistakes.
I really tried to make the example as simple as possible.
my code:
//global variables
...
double **testarray;
int dim;
...
int main(int argc, char **argv){
...
...
read_file("test.txt",&testarray,&dim);
}
int read_file(char* infilename,double ***arr,int *rowsout)
{
FILE* infile;
int i,j,ch,number_of_lines=0;
int rows=0;
//first count lines
if(myid==0) //myid is processor id
{
infile = fopen(infilename, "r");
do
{
ch = fgetc(infile);
if(ch == '\n')
number_of_lines++;
} while (ch != EOF);
if(ch != '\n' && number_of_lines != 0)
number_of_lines++;
//close file
fclose(infile);
rows=number_of_lines-1;
*rowsout=rows;
}
// every proc should know about length of file in order
//to be able to allocate memory
MPI_Bcast(rowsout,1,MPI_INT,0,MPI_COMM_WORLD);
//allocate memory
double *buf; //1D-buffer for 2D-array
MPI_Alloc_mem((*rowsout)*2*sizeof(double), MPI_INFO_NULL, &buf);
MPI_Alloc_mem((*rowsout)*sizeof(double*), MPI_INFO_NULL,arr);
for (i = 0; i < (*rowsout); i++) {
MPI_Alloc_mem(2*sizeof(double),MPI_INFO_NULL,&arr[i]);
}
// Now read file on proc 0
if(myid==0)
{
infile=fopen(infilename,"r");
for(i=0;i<rows;i++)
{
for(j=0;j<2;j++)
{
fscanf(infile,"%lf",arr[i][j]);
printf("arr[%d][%d]:%e\n",i,j,(*arr)[i][j]);
}
}
fclose(infile);
}
return 0;
//dont go further, error occurs before loop finishs
MPI_Bcast(buf,(rows)*2,MPI_DOUBLE,0,MPI_COMM_WORLD);
//now reconstruct array from buffer
for(i=0;i<(*rowsout);i++)
{
for(j=0;j<2;j++)
{
*arr[i][j]=buf[i*2+j];
}
}
MPI_Free_mem(buf);
return 0;
}
You have some issues with your arr as you guessed. Here is a fixed version of your code (minus the MPI stuff):
#include <stdio.h>
#include <stdlib.h>
void read_file(char *filename, double ***arr, int *rowsout);
int main(void)
{
double **testarray;
int dim;
read_file("test.txt", &testarray, &dim);
return 0;
}
void read_file(char *filename, double ***arr, int *rowsout)
{
FILE *infile;
int i, j, ch;
infile = fopen(filename, "r");
do
{
ch = fgetc(infile);
if (ch == '\n')
++*rowsout;
} while (ch != EOF);
rewind(infile);
*arr = malloc(sizeof **arr * *rowsout);
for (i = 0; i < *rowsout; ++i)
(*arr)[i] = malloc(sizeof ***arr * 2);
for (i = 0; i < *rowsout; ++i)
{
for (j = 0; j < 2; ++j)
{
fscanf(infile, "%lf", &(*arr)[i][j]);
printf("(*arr)[%d][%d]: %e\n", i, j, (*arr)[i][j]);
}
}
fclose(infile);
for (i = 0; i < *rowsout; ++i)
free((*arr)[i]);
free(*arr);
}
Example input: test.txt
0.01 0.02
0.3 0.4
5.0 6.0
Example output:
(*arr)[0][0]: 1.000000e-02
(*arr)[0][1]: 2.000000e-02
(*arr)[1][0]: 3.000000e-01
(*arr)[1][1]: 4.000000e-01
(*arr)[2][0]: 5.000000e+00
(*arr)[2][1]: 6.000000e+00
I believe the mistake comes with your fscanf() line. fscanf() wants a double * when you are using "%lf", but you are instead passing arr[i][j] and there's two things wrong with that: since arr is actually a pointer to your 2-D array, you will need to deference it first ((*arr)), and second, since it needs the address of the double, you will need to use &: &(*arr)[i][j].
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.
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