I am writing a program that opens numerous text files and reads from them parameters for planetary bodies. I have a problem when reading the text files.
sample text file
2
1, 1, 2
3.5, 3, 4
The first number (2) refers to the number of bodies found in the file. The next 2 lines correspond to the planet's parameters (x and y coordinates and mass respectively). I have 4 text files containing different amounts of bodies and need to store all the data in a variable.
my code
struct body {
float x;
float y;
float mass;
};
int main()
{
struct body b[8];
FILE *fp;
int i, j, k;
int num, count = 0;
char fName[10];
for (i = 1; i < 5; i++)
{
sprintf(fName,"bodies%d.txt",i);
fp = fopen(fName, "r");
if (fp == NULL)
{
printf("Can't open %s \n",fName);
exit(-1);
}
fscanf(fp, "%d", &num);
for (j = count; j < num; j++)
{
fscanf(fp, "%f%*c %f%*c %f%*c", &b[j].x, &b[j].y, &b[j].mass);
printf("%f %f %f\n", b[j].x, b[j].y, b[j].mass);
count = j;
}
}
It is reading the numbers from the text files, but it is stopping after 6 readings and there are 8 in total.
What could be the problem?
Your code has some problems:
fName is declared as
char fName[10];
and you use
sprintf(fName,"bodies%d.txt",i);
which writes 12 characters into fName(including the NUL-terminator) which can atmost hold 9 characters(+1 for the NUL-terminator).
The for loop:
for (j = count; j < num; j++)
{
fscanf(fp, "%f%*c %f%*c %f%*c", &b[j].x, &b[j].y, &b[j].mass);
printf("%f %f %f\n", b[j].x, b[j].y, b[j].mass);
count = j;
}
has many problems and is confusing too. When you do j = count, you check j < num. This makes no sense as count is not related to num.
Fixes:
For the first problem, allocate enough space for fName:
char fName[12];
instead of
char fName[10];
As for the second problem, use
for (j = 0; j < num; j++) //j should be initialized to 0
{
fscanf(fp, "%f%*c %f%*c %f%*c", &b[count].x, &b[count].y, &b[count].mass);
printf("%f %f %f\n", b[count].x, b[count].y, b[count].mass); //Use b[count] instead of b[j]
//count = j; Works, but the below is better
count++;
}
Try replacing j = count with j = 0 in the second for loop.
Related
#include <stdio.h>
int vowel_count(char n[]){
int hasil = 0;
char vowel[] = "aiueoyAIUEOY";
for (int i = 0; i < 50; i++)
{
for (int x = 0; x < 12; x++)
{
if (n[i] == vowel[x])
{
hasil++;
}
}
}
return hasil;
}
int main(void){
int amount;
char values[50], unknown[10];
char vowel[] = "AIUEOYaiueoy";
FILE* fp = fopen("zValues.txt", "r");
fscanf(fp, "%d", &amount);
fgets(unknown, 10, fp);
for (int n = 0; n < amount; n++)
{
fgets(values, 50, fp);
printf("%d ", vowel_count(values));
}
fclose(fp);
}
here is the zValues.txt:
5
abracadabra
pear tree
o a kak ushakov lil vo kashu kakao
my pyx
riszky hermawan
when i run the code,it shows:
5 4 13 12 12
see the problem? it's wrong answer"
ouput must be like this
5 4 13 2 5
Since your code uses the function, fgets to read the file content, the function vowel_count should not iterate over 50 array characters. Some of the lines (read from the file) may be of different length. Consequently, iterating beyond 50 characters may fetch random values from memory, which may include vowels.
Therefore you just need to adapt the function vowel_count, namely change:
for (int i = 0; i < 50; i++)
to
for (int i = 0; n[i] != '\0'; i++)
Moreover, IMO it is better to do :
for (int x = 0; vowel[x] != '\0'; x++)
instead of
for (int x = 0; x < 12; x++)
You do not need to hardcode the size of the array because when you write char vowel[] = "aiueoyAIUEOY", the terminal character (i.e. '\0') gets added automatically at the end of it. Although in your case is not very problematic, because the number of vowels will probably remain the same, in other cases, it is prone to bugs.
I have to parse a matrix from a file which first line characters are the rows and the cols count and the next lines are the matrix values.
The file contains:
3 3
R R B
B G G
G B R
I wrote the following code, but it crashes.
char** readMatrix(FILE *file) {
char *array;
int el = 0;
while (fscanf_s(file, "%s", array) != EOF) {
array[el] = array;
el++;
}
const int n = array[0] - '0', m = array[1] - '0';
char** matrix = malloc(n * sizeof(char*));
for (int i = 0; i < n; i++)
{
matrix[i] = malloc(m * sizeof(char));
}
int k = 2;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[i][j] = array[k];
++k;
}
}
return matrix;
}
The size of the matrix is different for the different files. How is it possible to declare a char array without knowing the size?
First you need to check if your FILE is not NULL ( it may crash cause of this )
if ( file == NULL ) {
printf("Error");
exit(1);
}
Then you need to be sure that your FILE's pointer is pointing at the start of the file :
fseek(file, 0, SEEK_SET);
If your rule is : 'The first line always contains two positive integer separate by a space and ending the line just after the second uint', then you can read them like this :
int dim_x = 0, dim_y = 0 ;
fscanf(file, "%d %d\n", &dim_x, &dim_y);
if(dim_x <= 0 || dim_y <= 0){
printf("Impossible to get correct the correct dimensions");
exit(1);
}
Then you can read your file line by line to have the correct data.
There is many variation to read your file. Assuming that any datas of your file are single characters spaced by 1 space or 1 backline, you can loop like this :
char ** matrix = (char**)malloc(sizeof(char*) * nbr_y);
for(int line = 0 ; line < nbr_y ; line ++){
matrix[line] = (char*)malloc(sizeof(char) * nbr_x);
for(int data_x_index = 0 ; data_x_index < nbr_x ; data_x_index ++){
fscanf(f, "%c", &matrix[line][data_x_index]); //Read and stock the character direclty in the matrix
fseek(f, 1, SEEK_CUR); // Go to the next character to read
}
}
for(int i = 0 ; i < nbr_y ; i ++){
for(int j = 0 ; j < nbr_x ; j ++){
printf("%c ", matrix[i][j]);
}
printf("\n");
}
}
Caution : This version is not checking if the text is well formated and if the dimensions are correct !
I have a project for school where I need to read in the values from a large text file and find the max and min number. This code works for a small text file where the numbers are like this
1
2
3
4
5
My question is how would I modify it so it would read in and find the max and min for a file that contained the numbers like so:
123
456
789
12345
1245676
EDIT: The numbers just post in a line. but basically I want my array to read in both columns and rows. Thanks
//inputting numbers from a text file, finding max and min in array and displaying them//
#include <stdio.h>
int main()
{ //Declare variables//
int size_of_array = 10;
int x[10] = {0};
int i;
int max;
int min;
FILE *input_fptr;
//open file for reading//
input_fptr = fopen("input.txt", "r");
if(input_fptr != NULL)
{
//Read in file contents//
for(i=0; i < size_of_array; i++)
{
fscanf(input_fptr,"%d", & x[i]);
}
fclose(input_fptr);
//min and max calculations//
max = x[0];
min = x[0];
for( i=0; i < size_of_array; i++)
{
if(x[i] > max)
{
max = x[i];
}
if(x[i] < min)
{
min = x[i];
}
}
}
//Print results//
printf("Largest element in array is : %d\n", max);
printf("Smallest element in array is : %d\n", min);
return 0;
}
You don't need an array to store the numbers. Just read one number at a time, comparing against the current max and min numbers.
In pseudo-ish code something like
int current_min = INT_MAX;
int current_max = INT_MIN;
while (read_one_number(&number))
{
if (number < current_min)
current_min = number;
if (number > current_max)
current_max = number;
}
And fscanf(input_fptr, "%d", ...) will read any space-delimited decimal integer. If the "space" is a newline, tab or normal space doesn't matter.
My professor gave us some code in class that will read in a matrix. However, it wont print out double values. If I have the following in a file
6.4 5.6 6.7
4.3 5.7 2.1
9.8 7.8 9.2
the code will round them down rather than printing out the actual double value. What needs to be changed? I have tried changing it to a double matrix, and printing it out using %g, etc.
#include <stdio.h>
#include <stdlib.h>
float** readMatrix(int *nRows, int *nCols);
main() {
//Holds our matrix of numbers
int nums[30][30];
float** m;
int r = 0, c = 0, i, j;
m = (float**)readMatrix(&r, &c);
for (i = 0; i < r; i++){
for (j = 0; j < c; j++) printf("%1.0f ", m[i][j]);
printf("\n");
}
}
//Read a matrix from standard input
float** readMatrix(int *nRows, int *nCols) {
int i = 0;
int j = 0;
int k = 0;
char c;
*nRows = 0; //The number of rows
*nCols = 0; //The number of columns
int nums[30][30];
char num[10];
while (1) {
//Read in the numbers on a row
j = 0; // j = the index of the number on the row - start at zero
while (1) {
//We will re-use the index i, so set to zero
i = 0;
//Read characters from standard input until a space or EOL
while ((c = getchar()) != ' ' && c != 10 && c != EOF) {
num[i++] = c;
}
//Null terminate the array of characters
num[i] = 0;
//Changes the array of characters to a float
nums[k][j++] = atof(num);
//If we are at the end of the line or end of file - break
if (c == 10 || c == EOF) break;
//Set the number of numbers
(*nCols) = j + 1;
}
//Stop if you are at the end of file
if (c == EOF) break;
//Go to the next row
k++;
} //End while(1) outer loop
*nRows = k;
//Allocate memory for the row pointers
float** retMat = (float**)malloc((*nRows)*sizeof(float*));
//Allocate memory for the rows themselves
for (i = 0; i < (*nRows); i++) retMat[i] = (float*)malloc((*nCols)*sizeof(float));
//Copy the nums matrix into the return matrix
for (i = 0; i < (*nRows); i++) for (j = 0; j < (*nCols); j++) retMat[i][j] = nums[i][j];
return retMat;
}
You are first reading into nums array which is of type int. Change that to float.
nums[k][j++]=atof(num);
atof returns float which is rounded down to int.
------EDIT-----------
printf("%1.0f ", m[i][j]);
This is reason why it prints wrong now. Check it.
I have a program (who's code is available at the bottom) which generates a list of numbers the way that I want it to. The program works fine as is and does exactly what I want. I'm just not a fan of the way I wrote it. It returns "Segmentation fault" if I change one thing, which I'll say at the bottom as well. Here's the code:
#include "stdio.h"
#include "stdlib.h"
#define NCH 81
// Generate swap-mode data for bonds for input.conf file
int main()
{
int i,j,k;
int **dat2, *dat;
//double *dat;
int ns = 500;
int nrow = NCH*(ns-1);
dat = (int*) calloc(nrow, sizeof(int));
dat2 = (int**) calloc(nrow,sizeof(int*));
for (i=0; i<nrow; i++) {
dat2[i] = (int*) calloc(2, sizeof(int));
for (j=0; j<2; j++)
dat2[i][j] = 0;
}
// Generates the bonds
k=2;
for (i=0; i<nrow; i++) {
k--;
for (j=0; j<2; j++) {
dat2[i][j] = k++;
if ( ((k%501) == 0) ) {
k--;
dat2[i][j] = k++;
k++;
}
}
}
FILE *inp2;
inp2 = fopen("bonds.out", "w");
for (i=1; i<=nrow; i++)
fprintf(inp2, "%d %d\n", dat2[i-1][0], dat2[i-1][1]);
fclose(inp2);
// Generates the bond ID in the pattern 1 2 3 3 2 1 ... (appropriate for Bond swap!)
k=1;
while ( k < nrow ) {
for (j=0; j<250; j++) {
dat[k] = (j+1);
k++;
}
for (j=250; j>0; j--) {
dat[k] = j;
k++;
}
}
// Scans bonds.out (because just reporting dat2[][] returns segmentation error, not sure why.
// scans the bonds.out file and stores both values into dm1 and dm2, then reports into 'results.out' file
int dm1, dm2;
FILE *inp;
inp = fopen("input.out", "w");
inp2 = fopen("bonds.out", "r");
for (i=1; i<=nrow; i++) {
fscanf(inp2, "%d %d", &dm1, &dm2);
fprintf(inp, "%d %d %d %d\n", i, dat[i], dm1, dm2);
}
printf("\nDone. All data has been written to \"input.out\"\n");
fclose(inp2);
fclose(inp);
return 0;
}
Now, I don't like the fact that it's first writing dat2[][] to a file and then scanning that file for the values. Why, instead, can't I incorporate dat2[][] in the main loop that writes the "results.out" file? If I do so, I get Segmentation fault. For clarification, I mean changing these lines in the code:
for (i=1; i<=nrow; i++) {
fscanf(inp2, "%d %d", &dm1, &dm2);
fprintf(inp, "%d %d %d %d\n", i, dat[i], dm1, dm2);
}
To these:
for (i=1; i<=nrow; i++) {
fprintf(inp, "%d %d %d %d\n", i, dat[i], dat2[i-1][0], dat2[i-1][1]);
}
I'd love an explanation as I'm still very new to C.
Thanks a lot!
Amit
I think you forgot to subtract 1 from the array index of dat, like this:
for (i=1; i<=nrow; i++) {
fscanf(inp2, "%d %d", &dm1, &dm2);
fprintf(inp, "%d %d %d %d\n", i, dat[i-1], dm1, dm2);
}
The reason why this causes a segfault is because you're looping until i <= nrow, which will go out of the bounds of dat on the final loop iteration.
I think there is something else on your code too besides what Relkin (correctly) pointed out.
int nrow = NCH*(ns-1);
dat = (int*) calloc(nrow, sizeof(int));
If my calculations are right, nrow == 81*(500-1) (== 40419) so it is dat[40419]
On the following explosive algorithm :
k=1;
while ( k < nrow ) {
for (j=0; j<250; j++) {
dat[k] = (j+1);
k++;
}
for (j=250; j>0; j--) {
dat[k] = j;
k++;
}
}
Every internal for loop increases k by 250 (so both increase it by 500 for every while loop), while k < 40419. This means there is a point where k reaches 40001, the condition is satisfied and the loop goes one more. At this moment, on the second for loop you exceed 40419 and write in memory you shouldn't. Take a look at that and check my maths again plz.
Once you are inside the while loop, and the condition falsifies, this does not mean the loop will automatically exit.