how to count rows and columns of integers/doubles in a file?

M

Martin Joergensen

Hi,

I have some files which has the following content:

0 0 0 0 0 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 0 0 0 0 0

I'm making a function for a bigger program, that

1) counts number of columns in each row
2) verifies that there are the same number of columns in each row
(if not: error + quit)
3) increments row count after one row is finished
4) stops execution if it encounters anything that is not an
integer (later: should also work for doubles)

My only problem is that I don't know how to switch line (carriage
return) or how to detect it using scanf. Besides that, the
program is almost finished. See below:
- - - - - - - - - - - - - - - -
#include <stdio.h>


void int_getdata(char *filename, unsigned int *x, unsigned int
*y);


int main()
{
unsigned int n_x[3], n_y[3];

int_getdata("unknowns.dat", &n_x[0], &n_y[0] );
int_getdata("BC_types.dat", &n_x[1], &n_y[1] );
// double_getdata("BC_values.dat", &n_x[2], &n_y[2] );

return 0;
}

void int_getdata(char *filename, unsigned int *x, unsigned int
*y)
{
FILE *fp;

unsigned int old_nx;
int int_readvalue, returnvalue;
//double double_readvalue;

old_nx = 0; /* reset */
*x = 0;
*y = 0;

if ( (fp = fopen(filename, "r") ) == NULL)
{
printf("Cannot open file %s.\n", filename);
system("PAUSE"); /* give the user at chance to see this
error before the windows shuts down */
exit(1);
}

/* get nx and ny */
do{
returnvalue = fscanf(fp, "%i", &int_readvalue); /* all
input must be valid */

if(returnvalue == 1) (*x)++; /* nx is getting larger */
else{
printf("Error: non-valid input found in %s.\n",
filename);
exit(1);
}

if(int_readvalue == '\n')
{
if(old_nx != 0 && old_nx != *x)
{
printf("ERROR: nx is not a constant in file
%s!\n", filename);
exit(1);
}
else /* we should now be sure that nx is constant and
move on to the next input line */
{
old_nx = *x;
y++; /* ny is getting larger */
*x = 0;
}
}
} while(returnvalue != EOF);

printf("\nFinished reading from file %s: (x,y) = (%i,%i).\n",
filename, *x, *y);
fclose(fp); /* close input file, finished reading values in
*/
}

- - - - - - - - - - - - - - - -

I hope somebody can help me solve this small problem, so I can
finish the program....

I also get these small warnings, but they are not critical:

warning C4013: 'system' undefined; assuming extern returning int

warning C4013: 'exit' undefined; assuming extern returning int


Best regards / Med venlig hilsen
Martin Jørgensen
 
M

Michael Mair

Martin said:
I have some files which has the following content:

0 0 0 0 0 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 0 0 0 0 0

I'm making a function for a bigger program, that

1) counts number of columns in each row
2) verifies that there are the same number of columns in each row (if
not: error + quit)
3) increments row count after one row is finished
4) stops execution if it encounters anything that is not an integer
(later: should also work for doubles)

My only problem is that I don't know how to switch line (carriage
return) or how to detect it using scanf.

The end of a line is indicated by '\n' in C.
If you are writing the file with a C programme, too, and
the reading and the writing programme are in the same locale,
then you do not have to take care of anything as long as you
work with text streams. Only if you explicitly open a binary
stream, then you have to look at the actual representation
of '\n'.
So, you can read in the number of lines and columns like this
if you concentrate on 1) to 3). You need some sort of string
buffer for 4) if you do not want to check yourself.

int countRowsAndCols (FILE *pFile, unsigned *pRows, unsigned *pCols)
{
unsigned rows, cols, oldcols;
int isConsistent = 1;

/* define file here */

rows = 0;
if (countColsInNextLine(pFile, &oldcols) != EOF) {
rows++;
while (countColsInNextLine(pFile, &cols) != EOF) {
rows++;
if (cols != oldcols) {
isConsistent = 0;
/* Your error message here */
}
}
}

*pRows = rows;
*pCols = oldcols;
return !isConsistent;
}

In
int countColsInNextLine (FILE *pFile, unsigned *pCols)
{
int c;
unsigned cols = 0;

do {
c = getc(pFile);
if (c != EOF && !isspace(c)) {
cols++;
do {
c = getc(pFile);
} while (c != EOF && !isspace(c));
}
while (c != EOF && c != '\n' && isspace(c)) {
c = getc(pFile);
}
} while (c != EOF && c != '\n')

*pCols = cols;
return c;
}
you consume characters from the file until you find
either a line break or the end of the file.
You return the last result from getc(), i.e. EOF if the
file ends. The functions are not tested.
You could make life easier in the second function by
introducing appropriate auxiliary functions.
The above is not tested.
Besides that, the program is
almost finished. See below:
- - - - - - - - - - - - - - - -
#include <stdio.h>


void int_getdata(char *filename, unsigned int *x, unsigned int *y);


int main()
{
unsigned int n_x[3], n_y[3];

int_getdata("unknowns.dat", &n_x[0], &n_y[0] );
int_getdata("BC_types.dat", &n_x[1], &n_y[1] );
// double_getdata("BC_values.dat", &n_x[2], &n_y[2] );

return 0;
}

void int_getdata(char *filename, unsigned int *x, unsigned int *y)
{
FILE *fp;

unsigned int old_nx;
int int_readvalue, returnvalue;
//double double_readvalue;

old_nx = 0; /* reset */
*x = 0;
*y = 0;

if ( (fp = fopen(filename, "r") ) == NULL)
{
printf("Cannot open file %s.\n", filename);
system("PAUSE"); /* give the user at chance to see this error
before the windows shuts down */
exit(1);
}

/* get nx and ny */
do{
returnvalue = fscanf(fp, "%i", &int_readvalue); /* all input must
be valid */

if(returnvalue == 1) (*x)++; /* nx is getting larger */
else{
printf("Error: non-valid input found in %s.\n", filename);
exit(1);
}

if(int_readvalue == '\n')

This is not what you want. You compare the value of the read
integer against the value of the int constant '\n'.
{
if(old_nx != 0 && old_nx != *x)
{
printf("ERROR: nx is not a constant in file %s!\n",
filename);
exit(1);
}
else /* we should now be sure that nx is constant and move on
to the next input line */
{
old_nx = *x;
y++; /* ny is getting larger */
*x = 0;
}
}
} while(returnvalue != EOF);

printf("\nFinished reading from file %s: (x,y) = (%i,%i).\n",
filename, *x, *y);
fclose(fp); /* close input file, finished reading values in */
}

- - - - - - - - - - - - - - - -

I hope somebody can help me solve this small problem, so I can finish
the program....

Even though you can do certain things with the help of
scan sets (%[] or %[^]), it is probably easier to read in
a line and check the values with sscanf() or even strtoul()
or strtod(). If you only need the originally indicated
space -- non-space distinction, have a look at the suggested
functions.
We already lead the "how to read a line" discussion, so you
can just look up the respective thread.

I also get these small warnings, but they are not critical:

warning C4013: 'system' undefined; assuming extern returning int

warning C4013: 'exit' undefined; assuming extern returning int

They are. You forgot to #include <stddef.h>, so you did not get
proper types for the functions.
Especially, the arguments are not converted automatically and
you don't get a warning if they cannot be converted. For these
two functions, everything probably will work as intended but
there is a serious error behind the warning.


Cheers
Michael
 
K

Keith Thompson

Martin Joergensen said:
I have some files which has the following content:

0 0 0 0 0 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 0 0 0 0 0

I'm making a function for a bigger program, that

1) counts number of columns in each row

What do you mean by "columns"? Does "0 0 0 0 0 0" have 6 columns
(numbers) or 11 (characters)?

[snip]
returnvalue = fscanf(fp, "%i", &int_readvalue); /* all input
must be valid */

fscanf with a "%i" format reads an integer value after skipping any
leading whitespace -- including new-lines. It gives no indication of
what it skipped. If new-lines are significant, that's the wrong
approach.

It also accepts either decimal, octal, or hexadecimal input. Decide
whether you want to allow numbers like "0xff", and whether you want
"0123" to be interpreted in octal (yielding 83) or in decimal
(yielding 123). Since you mentioned you'll eventually want the
program to work with doubles, you probably don't want to accept octal
or hexadecimal; you probably want "%d" rather than "%i". ("%d" and
"%i" behave identically for the *printf functions, but differently for
the *scanf functions).

A much better approach is to use fgets() to read a line at a time,
then use sscanf() to scan the resulting line. sscanf(), unlike
fscanf(), doesn't consume its input; it's still there in the string,
and if the sscanf() call fails (check its returned value), you can try
again.

fgets() has the disadvantage that it can only read a line up to a
specified length. If the input line is longer than what you
specified, fgets() will read only part of it; you can detect this by
whether the line you just read ends in a '\n'. If you only want to
allow input lines up to some maximum length, this isn't much of a
problem -- but you should still decide what to do if an input line
exceeds your maximum. If you want to handle arbitrarily long input
lines, you can use CBFalconer's "ggets" (Google it).
 
B

Barry Schwarz

Hi,

I have some files which has the following content:

0 0 0 0 0 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 0 0 0 0 0

I'm making a function for a bigger program, that

1) counts number of columns in each row
2) verifies that there are the same number of columns in each row
(if not: error + quit)
3) increments row count after one row is finished
4) stops execution if it encounters anything that is not an
integer (later: should also work for doubles)

My only problem is that I don't know how to switch line (carriage
return) or how to detect it using scanf. Besides that, the
program is almost finished. See below:
- - - - - - - - - - - - - - - -
#include <stdio.h>


void int_getdata(char *filename, unsigned int *x, unsigned int
*y);


int main()
{
unsigned int n_x[3], n_y[3];

int_getdata("unknowns.dat", &n_x[0], &n_y[0] );
int_getdata("BC_types.dat", &n_x[1], &n_y[1] );
// double_getdata("BC_values.dat", &n_x[2], &n_y[2] );

return 0;
}

void int_getdata(char *filename, unsigned int *x, unsigned int
*y)
{
FILE *fp;

unsigned int old_nx;
int int_readvalue, returnvalue;
//double double_readvalue;

old_nx = 0; /* reset */
*x = 0;
*y = 0;

if ( (fp = fopen(filename, "r") ) == NULL)
{
printf("Cannot open file %s.\n", filename);
system("PAUSE"); /* give the user at chance to see this
error before the windows shuts down */
exit(1);
}

/* get nx and ny */
do{
returnvalue = fscanf(fp, "%i", &int_readvalue); /* all
input must be valid */

fscanf will eat white space, including the \n that marks the end of
line.

You could use fgets to get a complete line then strtol to process each
value for correctness.
if(returnvalue == 1) (*x)++; /* nx is getting larger */
else{
printf("Error: non-valid input found in %s.\n",
filename);
exit(1);
}

if(int_readvalue == '\n')
{
if(old_nx != 0 && old_nx != *x)
{
printf("ERROR: nx is not a constant in file
%s!\n", filename);
exit(1);
}
else /* we should now be sure that nx is constant and
move on to the next input line */
{
old_nx = *x;
y++; /* ny is getting larger */
*x = 0;
}
}
} while(returnvalue != EOF);

printf("\nFinished reading from file %s: (x,y) = (%i,%i).\n",
filename, *x, *y);
fclose(fp); /* close input file, finished reading values in
*/
}

- - - - - - - - - - - - - - - -

I hope somebody can help me solve this small problem, so I can
finish the program....

I also get these small warnings, but they are not critical:

warning C4013: 'system' undefined; assuming extern returning int

warning C4013: 'exit' undefined; assuming extern returning int


Best regards / Med venlig hilsen
Martin Jørgensen


Remove del for email
 
M

Martin Joergensen

Michael Mair said:
Martin Joergensen schrieb: -snip-

The above is not tested.

Thanks... Helped me a lot... Almost finished now... Se my other
post.
This is not what you want. You compare the value of the read
integer against the value of the int constant '\n'.

Oh, yeah... I hoped that it could read integers as well as
'\n'... Seems like it can't. I just skips it..

-snip-
Even though you can do certain things with the help of
scan sets (%[] or %[^]), it is probably easier to read in
a line and check the values with sscanf() or even strtoul()
or strtod(). If you only need the originally indicated
space -- non-space distinction, have a look at the suggested
functions.

Ok... I added a little - I also want to skip commas.

That was also so great about scanf, that it could check if all
numbers were valid at the same time it counted...
We already lead the "how to read a line" discussion, so you
can just look up the respective thread.

I found something on google:
- - - - -- -
#define LENGTH 20
#define str(x) # x
#define xstr(x) str(x)

int rc;
char array[LENGTH + 1];


rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) {
getchar();
}
if (rc == 0) {
*array = '\0';
}


/* rc will be either 1, 0, or EOF */

- - - - -

What the hell is happening here: "[^\n]%*[^\n]" ?
They are. You forgot to #include <stddef.h>, so you did not get
proper types for the functions.

No, I think it is stdlib.h, I needed... But thanks - you're
always a big help to me...
Especially, the arguments are not converted automatically and
you don't get a warning if they cannot be converted. For these
two functions, everything probably will work as intended but
there is a serious error behind the warning.

Ok, including stdlib.h seems to work...


Best regards / Med venlig hilsen
Martin Jørgensen
 
M

Martin Joergensen

Keith Thompson said:
A much better approach is to use fgets() to read a line at a
time,
then use sscanf() to scan the resulting line. sscanf(), unlike
fscanf(), doesn't consume its input; it's still there in the
string,
and if the sscanf() call fails (check its returned value), you
can try
again.
-snip-

What do you think about the following, based on Michael Mair's
proposal?

Just copy/paste - compiles well...
- - - - - -
#include <stdlib.h> /* system("PAUSE") */
#include <stdio.h>
#include <stddef.h>
#include <ctype.h> /* for isspace */

#define number_of_files 3

/* prototypes */
void getdata(char *filename, unsigned *pRows, unsigned *pCols);
/* this is how the args should be */
int countColsInNextLine (FILE *pFile, unsigned *pCols);


int main()
{
int i;
unsigned n_x[number_of_files], n_y[number_of_files]; /* one
space for each data file */

getdata("unknowns.dat", &n_x[0], &n_y[0] );
getdata("BC_types.dat", &n_x[1], &n_y[1] );
// getdata("BC_values.dat", &n_x[2], &n_y[2] );

for(i=0; i<number_of_files; i++)
printf("Data file number %i has properties: x = %u, y=
%u\n", i, n_x, n_y);

return 0;
}

//fgets( stringbuffer, 20, fp);
//sscanf( stringbuffer, "%X", &var1);

void getdata(char *filename, unsigned *pRows, unsigned *pCols) /*
this is how the args should be */
{
FILE *pFile;

unsigned rows, cols, oldcols;

if ( (pFile = fopen(filename, "r") ) == NULL)
{
printf("Cannot open file %s.\n", filename);
system("PAUSE"); /* give the user at chance to see this
error before the windows shuts down */
exit(1);
}

*pRows = 0;
*pCols = 0;

/* get nx and ny */
cols = 0;
rows = 0;
if (countColsInNextLine(pFile, &oldcols) != EOF) { /* get
oldcols for first row */
rows++;
while (countColsInNextLine(pFile, &cols) != EOF) {
rows++;
if (cols != oldcols) { /* verify that number of cols
didn't change */
printf("ERROR: Number of columns is not a
constant in file: %s!\n", filename);
exit(1);
}
}
}

*pRows = rows; /* update results */
*pCols = oldcols;

printf("\nFinished reading from file %s.\n", filename);
fclose(pFile); /* close input file, finished reading values
in */
}

int countColsInNextLine (FILE *pFile, unsigned *pCols)
{
int c;
unsigned cols = 0;

do {
c = getc(pFile); /* get first character to start the loop
*/
if (c != EOF && !isspace(c)) { /* first time non-space
encountered, update cols */
cols++;
do { /* skip digits and commas */
c = getc(pFile);
} while (c != EOF && !isspace(c) && c != ',' && c !=
'.'); /* comma should also be valid input in number */
}
while (c != EOF && c != '\n' && isspace(c)) { /* skip
through spaces, but not '\n' ! */
c = getc(pFile);
}
} while (c != EOF && c != '\n');

*pCols = cols;
return c;
}
- - - -
It seems like there is small error in counting the rows..... I
couldn't find the error before and I'm not sure I understood all
the while loops completely - to help myself I added some
comments.

So there's just a little error left (that's the second time in
this thread I write that - This time I hope it's true!) :)


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Martin said:
"Keith Thompson" <[email protected]> skrev i en meddelelse
-snip-

What do you think about the following, based on Michael Mair's proposal?
-snip-

I don't know why, but I can't debug that code very well... I put
breakpoints in it but very often within the getdata-function, it just
finishes the program ignoring my breakpoints....

Why is that so?


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Martin said:
-snip-

I don't know why, but I can't debug that code very well... I put
breakpoints in it but very often within the getdata-function, it just
finishes the program ignoring my breakpoints....

Why is that so?

Forget it... I forgot to add a compiler option and now it works.


Best regards / Med venlig hilsen
Martin Jørgensen
 
M

Michael Mair

rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);
What the hell is happening here: "[^\n]%*[^\n]" ?

read up to LENGTH non-'\n' characters into array, consume
arbitrarily many subsequent '\n's
No, I think it is stdlib.h, I needed... But thanks - you're always a big
help to me...

"Left, left -- oh, I meant the other left"
Of course, you are right: I meant <stdlib.h>

Cheers
Michael
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Michael Mair wrote:
-snip-
Cheers
Michael

Do you like my new program?

I find it *REALLY* useful :)

- - - - - - - - - - - -

#include <stdlib.h> /* system("PAUSE") */
#include <stdio.h>
#include <stddef.h>
#include <ctype.h> /* for isspace */

#define max_number_of_files 50

/* prototypes */
void getdata(char *filename, unsigned *pCols, unsigned *pRows, int *count);
int countColsInNextLine (FILE *pFile, unsigned *pCols, unsigned *pRows);
void testwronginput(int c, unsigned cols, unsigned rows);

int main()
{
int i, count;
unsigned n_x[max_number_of_files], n_y[max_number_of_files]; /* one
space for each data file */

count = 0;
getdata("unknowns.dat", &n_x[0], &n_y[0], &count );
getdata("BC_types.dat", &n_x[1], &n_y[1], &count );
getdata("BC_values.dat", &n_x[2], &n_y[2], &count );

for(i=0; i<count; i++)
printf("Data file number %i has properties: Columns (x) = %u,
Rows y= %u\n", i+1, n_x, n_y);

system("PAUSE"); /* give the user at chance to see this error
before the windows shuts down */
return 0;
}


void getdata(char *filename, unsigned *pCols, unsigned *pRows, int *count)
{
FILE *pFile;

unsigned rows, cols, oldcols;

printf("Opening file: %s.\n", filename);
if ( (pFile = fopen(filename, "r") ) == NULL)
{
printf("Cannot open file %s.\n", filename);
system("PAUSE"); /* give the user at chance to see this error
before the windows shuts down */
exit(1);
}

*pRows = 0;
*pCols = 0;

/* get nx and ny */
cols = 0;
rows = 0;
if (countColsInNextLine(pFile, &oldcols, &rows) != EOF) { /* return
oldcols for first row */
rows++;
while (countColsInNextLine(pFile, &cols, &rows) != EOF) { /*
check row 2 -> EOF */
rows++;
if (cols != oldcols) { /* verify that number of cols didn't
change */
printf("ERROR: Number of columns is not a constant in
file: %s\n\n", filename);
printf("In line %u, the number of columns is %u
cols.\n", rows, cols);
printf("In the previous line it was counted to
%u.\n\nPlease fix this problem now.\n", oldcols);
exit(1);
}
}
}

if (cols != 0 && cols != oldcols) {
printf("ERROR: Line %u (last line) consisted of %u
columns.\nLine %u had %u columns.\n", rows, cols, rows-1, oldcols);
exit(1);
}

*pRows = rows; /* update results */
*pCols = oldcols;
(*count)++;

printf("Finished reading from file %s.\n\n", filename);
fclose(pFile); /* close input file, finished reading values in */
}

int countColsInNextLine (FILE *pFile, unsigned *pCols, unsigned *pRows)
{
int c;
unsigned cols = 0;

c = getc(pFile); /* get first character to start the loop */
do {
testwronginput(c, cols, *pRows);
if (c != EOF && !isspace(c)) { /* first time non-space
encountered, update cols */
cols++;
do { /* skip digits and commas, after first digit */
c = getc(pFile);
testwronginput(c, cols, *pRows);
} while (c != EOF && !isspace(c) || c == ',' || c == '.');
/* comma should also be valid input in number */
}
while (c != EOF && c != '\n' && isspace(c)) { /* skip through
blank spaces, but not '\n' ! */
c = getc(pFile);
testwronginput(c, cols, *pRows);
}
} while (c != EOF && c != '\n'); /* is the line finished or is EOF
reached? */

*pCols = cols;
return c;
}

void testwronginput(int c, unsigned cols, unsigned rows) /* I tried
isblank() but my system complained about it */
{
if (isalpha(c)) {
printf("Error! Alphabetic character '%c' encountered before
EOF\n", c);
printf("Last succesful location read was: Line %u, Column
%u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see this error
before the windows shuts down */
exit(1);
}
if (iscntrl(c) && c != 10) {
printf("Error! Control character '%c' encountered before
EOF\n", c);
printf("Last succesful location read was: Line %u, Column
%u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see this error
before the windows shuts down */
exit(1);
}
if (!isprint(c) && c != EOF && c != '\n') {
printf("Error! Non-printing character '%c' encountered before
EOF\n", c);
printf("Last succesful location read was: Line %u, Column
%u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see this error
before the windows shuts down */
exit(1);
}
}

- - - - - - - - - - - -


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Martin said:
Michael Mair wrote:
-snip-



Do you like my new program?
-snip-

I have a serious problem now!

I thought everything was okay and was progressing well - So I now
figured out how to do this program but now I want to include it in my
bigger program and use number of cols + number of rows to malloc().

So, I have a lot of arrays that depend on malloc() which again should
depend on number of rows in x-direction = nx, and number of cols in
y-direction = ny.

So my big program starts with something like:
- - - - - - - - - - - -

int main(void)
{

/* prototypes */
void int_fillinnumbers(int, int, int, int, int, int **);
void double_fillinnumbers(double, int, int, int, int, double **);
void int_printout(int, int, int, int, int **);
void double_printout(int, int, int, int, double **);
void conversion(int no, int *i, int *j); /* convert from number of
interior cells to [j] format */
void one_dim_double_printout(int startx, int stopx, double *array); /*
for printing out temperatures from CG-solver */
void integer_load_properties(char *filename, int **array);
void double_load_properties(char *filename, double **array);

pstSolveType pstSolve;


// // // // // //

/* STOP READING HERE! Now, I need the number of cols and rows from the
data-files to dynamically initialize the correct 1D and 2D-array sizes.
I need it here, because below malloc need number of cols */

// // // // // //


double **T = malloc((cols+1)*sizeof(double*)); /* alternative: int **T
= malloc((cols + 1) * sizeof *T); */
double **T_new = malloc((cols+1)*sizeof(double*));

.. . . . . .
.. . . . . . (later)
.. . . . . .

T[0] = malloc((cols+1)*(rows+1)*sizeof(double));
T_new[0] = malloc((cols+1)*(rows+1)*sizeof(double));



The problem is that I get a compiler error, something about a missing
semi-colon. And I've got this error a couple of times before. I happens
because I mix declarations and initialisation, somebody wrote...

What the hell do I do now? Until now, rows and columns was just set to
something using #define, but I don't like that solution with having to
change input data several places, both in the #define line and also in
each input file(s)...

So, what I want is to include these lines:

count = 0;
getdata("unknowns.dat", &n_x[0], &n_y[0], &count );
getdata("BC_types.dat", &n_x[1], &n_y[1], &count );
getdata("BC_values.dat", &n_x[2], &n_y[2], &count );

for(i=0; i<count; i++)
printf("Data file number %i has properties: Columns (x) = %u,
Rows y= %u\n", i+1, n_x, n_y);


But then the compiler is complaining like hell, because I need to the
return value of *n_x and *n_y for malloc(), *count is just a counter for
number of read files...

I really, *really* hope there is a good solution to this problem. I just
have no idea what it is.

Please let me know, if you have any ideas whatsoever. I almost can't
believe that there's no way of dealing with this problem in a good way.


Best regards / Med venlig hilsen
Martin Jørgensen
 
B

Barry Schwarz

Martin said:
Michael Mair wrote:
-snip-



Do you like my new program?
-snip-

I have a serious problem now!

I thought everything was okay and was progressing well - So I now
figured out how to do this program but now I want to include it in my
bigger program and use number of cols + number of rows to malloc().

So, I have a lot of arrays that depend on malloc() which again should
depend on number of rows in x-direction = nx, and number of cols in
y-direction = ny.

So my big program starts with something like:
- - - - - - - - - - - -

int main(void)
{

/* prototypes */
void int_fillinnumbers(int, int, int, int, int, int **);
void double_fillinnumbers(double, int, int, int, int, double **);
void int_printout(int, int, int, int, int **);
void double_printout(int, int, int, int, double **);
void conversion(int no, int *i, int *j); /* convert from number of
interior cells to [j] format */
void one_dim_double_printout(int startx, int stopx, double *array); /*
for printing out temperatures from CG-solver */
void integer_load_properties(char *filename, int **array);
void double_load_properties(char *filename, double **array);

pstSolveType pstSolve;


// // // // // //

/* STOP READING HERE! Now, I need the number of cols and rows from the
data-files to dynamically initialize the correct 1D and 2D-array sizes.
I need it here, because below malloc need number of cols */

// // // // // //


double **T = malloc((cols+1)*sizeof(double*)); /* alternative: int **T
= malloc((cols + 1) * sizeof *T); */


In most implementations, rows come before columns.
double **T_new = malloc((cols+1)*sizeof(double*));

. . . . . .
. . . . . . (later)
. . . . . .

T[0] = malloc((cols+1)*(rows+1)*sizeof(double));

Since you already have cols+1 pointers, each pointer only needs to
point to rows+1 doubles, not (cols+1)*(rows+1).
T_new[0] = malloc((cols+1)*(rows+1)*sizeof(double));



The problem is that I get a compiler error, something about a missing
semi-colon. And I've got this error a couple of times before. I happens
because I mix declarations and initialisation, somebody wrote...

Missing semicolon errors are usually caused by an error preceding the
actual line flagged. You need to show us all the code.
What the hell do I do now? Until now, rows and columns was just set to
something using #define, but I don't like that solution with having to
change input data several places, both in the #define line and also in
each input file(s)...

So, what I want is to include these lines:

count = 0;
getdata("unknowns.dat", &n_x[0], &n_y[0], &count );
getdata("BC_types.dat", &n_x[1], &n_y[1], &count );
getdata("BC_values.dat", &n_x[2], &n_y[2], &count );

for(i=0; i<count; i++)
printf("Data file number %i has properties: Columns (x) = %u,
Rows y= %u\n", i+1, n_x, n_y);


But then the compiler is complaining like hell, because I need to the
return value of *n_x and *n_y for malloc(), *count is just a counter for
number of read files...


Show the code. Your explanation is borderline meaningless.
I really, *really* hope there is a good solution to this problem. I just
have no idea what it is.

Please let me know, if you have any ideas whatsoever. I almost can't
believe that there's no way of dealing with this problem in a good way.


Best regards / Med venlig hilsen
Martin Jørgensen


Remove del for email
 
M

Mark F. Haigh

Martin said:
Michael Mair wrote:
-snip-


Do you like my new program?

<snip>

Here's some help. Compile this small program, and run it with the
filename of your .dat file as the command line argument. Try all the
cases you can think of, and see how the error handling works.


#include <stdio.h>
#include <stdlib.h>

enum Error {
Success, /* All went well */
TooManyCol, /* Too many columns */
TooFewCol, /* Too few columns */
ConvErr, /* Conversion failed */
FileErr /* File read error */
};

/*
* Parse a file to determine the number of rows and columns of integer
* data. Lines containing only whitespace are ignored. If the return
* value is not Success, the line number in the file where the problem
* was encountered is written to *rows. If a fscanf conversion error
* occurred, then the current position of 'fp' will be the position of
* the problematic input.
*/
enum Error parse(FILE *fp, int *rows, int *cols)
{
int line, count, ret, val;
enum Error err = Success;

*rows = *cols = 0;
for(line = 1; ; line++) {
for(count = 0; ; count++) {

/* Discard spaces and tabs. */
ret = fscanf(fp, "%*[ \t]");
if(ret == EOF)
break;

/* Get the next character. */
ret = getc(fp);
if(ret == EOF)
break;

/* At the end of the line? */
if(ret == '\n')
break;

/* No. Put back and fscanf. */
ungetc(ret, fp);
ret = fscanf(fp, "%d", &val);
if(ret != 1) {
if(ret == 0)
err = ConvErr;
break;
}
}

/* Check for file error. */
if(ret == EOF && ferror(fp))
err = FileErr;

/* If successful so far... */
if(err == Success) {
if(count != 0) {
(*rows)++;
if(*cols == 0)
*cols = count;
else {
if(count < *cols)
err = TooFewCol;
else if(count > *cols)
err = TooManyCol;
}
}
}

/* If an error or EOF, stop */
if(err != Success || feof(fp))
break;
}

/* On error, report line number. */
if(err != Success)
*rows = line;
return err;
}


int main(int argc, char *argv[])
{
FILE *fp;
int rows, cols;
enum Error result;
const char *file;
int ret = EXIT_FAILURE;
char buf[8];

/* Check argument count. */
if(argc != 2) {
printf("usage: %s FILENAME\n", argv[0]);
return ret;
}

/* Open the data file. */
file = argv[1];
fp = fopen(file, "r");
if(fp == NULL) {
printf("Error: cannot open %s.\n", file);
return ret;
}

/* Try to parse the file, then interpret the result. */
result = parse(fp, &rows, &cols);
switch(result) {
case Success:
printf("%s: %d rows, %d columns\n", file,
rows, cols);
ret = EXIT_SUCCESS;
break;

case TooManyCol:
printf("Error: %s line %d: too many columns.\n",
file, rows);
break;

case TooFewCol:
printf("Error: %s line %d: too few columns.\n",
file, rows);
break;

case ConvErr:
fscanf(fp, "%7s", buf);
printf("Error: %s line %d: invalid input near \"%s\".\n",
file, rows, buf);
break;

case FileErr:
default:
printf("Error: %s line %d: unknown file error.\n",
file, rows);
break;
}

/* Clean up and exit */
fclose(fp);
return ret;
}


Report back with any comments, questions, or bugs. I wrote it over
lunch, so it may contain a bug or two.


Mark F. Haigh
(e-mail address removed)
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Barry said:
On Fri, 17 Mar 2006 19:00:51 +0100, Martin Jørgensen



In most implementations, rows come before columns.

Damn... I think you're right....... I should change it - Only went good
because number of rows = number of cols...
double **T_new = malloc((cols+1)*sizeof(double*));

. . . . . .
. . . . . . (later)
. . . . . .

T[0] = malloc((cols+1)*(rows+1)*sizeof(double));


Since you already have cols+1 pointers, each pointer only needs to
point to rows+1 doubles, not (cols+1)*(rows+1).

But I *don't* have number of cols and number of rows from my program
using the above implementation. In the above implementation, I just did
a #define cols 8 (or whatever). As I wrote, the problem is that I don't
want to change both #define rows and the input file. Only the input file..
T_new[0] = malloc((cols+1)*(rows+1)*sizeof(double));



The problem is that I get a compiler error, something about a missing
semi-colon. And I've got this error a couple of times before. I happens
because I mix declarations and initialisation, somebody wrote...


Missing semicolon errors are usually caused by an error preceding the
actual line flagged. You need to show us all the code.

Well, I guess you saw my program but perhaps didn't notice it very much,
so here I just took some parts to show you the structure of what I want
(untested, but then you know what this is about):

- - - - -

/* prototypes */
/* several ones bla.bla.bla. from the bigger program I have */

/* more prototypes */
void getdata(char *filename, unsigned *pCols, unsigned *pRows, int
*count);
int countColsInNextLine (FILE *pFile, unsigned *pCols, unsigned
*pRows);
void testwronginput(int c, unsigned cols, unsigned rows);


int main(void)
{
/* read from file and get number of cols+rows */

unsigned count; /* and a lot more var's, not necessary in this
example */
double **T, **T_new;

count = 0; /* keep track of number of datafiles read */
getdata("unknowns.dat", &n_x[0], &n_y[0], &count );
getdata("BC_types.dat", &n_x[1], &n_y[1], &count );
getdata("BC_values.dat", &n_x[2], &n_y[2], &count );

/* error-testing if number of rows+cols is the same in all files,
i.e: n_x[0] = n_x[1] = n_x[2] and the same for n_y */

double **T = malloc((n_y[0]+1)*sizeof(double*)); /* n_y = rows */
double **T_new = malloc((ny[0]+1)*sizeof(double*)); /* n_y = rows */

/*. . . . . .
.. . . . . . (later)
.. . . . . . */

T[0] = malloc((n_x[0]+1)*(n_y[0]+1)*sizeof(double)); /* nx= cols */
T_new[0] = malloc((n_x[0]+1)*(n_y[0]+1)*sizeof(double)); /* nx= cols */
}


void getdata(char *filename, unsigned *pCols, unsigned *pRows, int *count)
{
FILE *pFile;

unsigned rows, cols, oldcols;

printf("Opening file: %s.\n", filename);
if ( (pFile = fopen(filename, "r") ) == NULL)
{
printf("Cannot open file %s.\n", filename);
system("PAUSE"); /* give the user at chance to see this error
before the windows shuts down */
exit(1);
}

*pRows = 0;
*pCols = 0;

/* get nx and ny */
cols = 0;
rows = 0;
if (countColsInNextLine(pFile, &oldcols, &rows) != EOF) { /* return
oldcols for first row */
rows++;
while (countColsInNextLine(pFile, &cols, &rows) != EOF) { /*
check row 2 -> EOF */
rows++;
if (cols != oldcols) { /* verify that number of cols didn't
change */
printf("ERROR: Number of columns is not a constant in
file: %s\n\n", filename);
printf("In line %u, the number of columns is %u
cols.\n", rows, cols);
printf("In the previous line it was counted to
%u.\n\nPlease fix this problem now.\n", oldcols);
exit(1);
}
}
}

if (cols != 0 && cols != oldcols) {
printf("ERROR: Line %u (last line) consisted of %u
columns.\nLine %u had %u columns.\n", rows, cols, rows-1, oldcols);
exit(1);
}

*pRows = rows; /* update results */
*pCols = oldcols;
(*count)++;

printf("Finished reading from file %s.\n\n", filename);
fclose(pFile); /* close input file, finished reading values in */
}

int countColsInNextLine (FILE *pFile, unsigned *pCols, unsigned *pRows)
{
int c;
unsigned cols = 0;

c = getc(pFile); /* get first character to start the loop */
do {
testwronginput(c, cols, *pRows);
if (c != EOF && !isspace(c)) { /* first time non-space
encountered, update cols */
cols++;
do { /* skip digits and commas, after first digit */
c = getc(pFile);
testwronginput(c, cols, *pRows);
} while (c != EOF && !isspace(c) || c == ',' || c == '.');
/* comma should also be valid input in number */
}
while (c != EOF && c != '\n' && isspace(c)) { /* skip through
blank spaces, but not '\n' ! */
c = getc(pFile);
testwronginput(c, cols, *pRows);
}
} while (c != EOF && c != '\n'); /* is the line finished or is EOF
reached? */

*pCols = cols;
return c;
}

void testwronginput(int c, unsigned cols, unsigned rows) /* I tried
isblank() but my system complained about it */
{
if (isalpha(c)) {
printf("Error! Alphabetic character '%c' encountered before
EOF\n", c);
printf("Last succesful location read was: Line %u, Column
%u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see this error
before the windows shuts down */
exit(1);
}
if (iscntrl(c) && c != 10) {
printf("Error! Control character '%c' encountered before
EOF\n", c);
printf("Last succesful location read was: Line %u, Column
%u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see this error
before the windows shuts down */
exit(1);
}
if (!isprint(c) && c != EOF && c != '\n') {
printf("Error! Non-printing character '%c' encountered before
EOF\n", c);
printf("Last succesful location read was: Line %u, Column
%u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see this error
before the windows shuts down */
exit(1);
}
}

-snip-
Show the code. Your explanation is borderline meaningless.

See above.



Best regards / Med venlig hilsen
Martin Jørgensen
 
M

Martin Joergensen

"Barry Schwarz" <[email protected]> skrev i en meddelelse
-snip-
Show the code. Your explanation is borderline meaningless.

Ok, forget everything I wrote earlier... I just need to know how
to fix the following code (3 warnings, 2 errors).

- - - -- - -- - - - -- - --
#include <stdlib.h> /* system("PAUSE") */
#include <stdio.h>
#include <stddef.h>
#include <ctype.h> /* for isspace */

/* defintions */
#define max_input_files 3

/* more prototypes */
void getdata(char *filename, unsigned *pCols, unsigned *pRows,
int *count);
int countColsInNextLine(FILE *pFile, unsigned *pCols, unsigned
*pRows);
void testwronginput(int c, unsigned cols, unsigned rows);


int main(void)
{
/* read from file and get number of cols+rows */

unsigned count, n_x[max_input_files], n_y[max_input_files];
/* and a lot more var's, not necessary in this example */
double **T, **T_new;

count = 0; /* keep track of number of datafiles read */
getdata("inputfile1.dat", &n_x[0], &n_y[0], &count );
getdata("inputfile2.dat", &n_x[1], &n_y[1], &count );
if(n_x[0] != n_x[1] && n_y[0] != n_y[1])
exit(1);
getdata("inputfile3.dat", &n_x[2], &n_y[2], &count );
if(n_x[1] != n_x[2] && n_y[1] != n_y[2])
exit(1);

double **T = malloc((n_y[0]+1)*sizeof(double*)); /* n_y =
rows */
double **T_new = malloc((n_y[0]+1)*sizeof(double*)); /* n_y =
rows */

T[0] = malloc((n_x[0]+1)*(n_y[0]+1)*sizeof(double)); /* nx=
cols */
T_new[0] = malloc((n_x[0]+1)*(n_y[0]+1)*sizeof(double)); /*
nx= cols */

/* eventually test with T[4][6] = 959, and printf("%lf",
T[4][6]); etc... */
}


void getdata(char *filename, unsigned *pCols, unsigned *pRows,
int *count)
{
FILE *pFile;

unsigned rows, cols, oldcols;

printf("Opening file: %s.\n", filename);
if ( (pFile = fopen(filename, "r") ) == NULL)
{
printf("Cannot open file %s.\n", filename);
system("PAUSE"); /* give the user at chance to see this
error
before the windows shuts down */
exit(1);
}

*pRows = 0;
*pCols = 0;

/* get nx and ny */
cols = 0;
rows = 0;
if (countColsInNextLine(pFile, &oldcols, &rows) != EOF) { /*
return
oldcols
for first row */
rows++;
while (countColsInNextLine(pFile, &cols, &rows) != EOF)
{ /*

check row 2 -> EOF */
rows++;
if (cols != oldcols) { /* verify that number of cols
didn't
change */
printf("ERROR: Number of columns is not a
constant in file: %s\n\n", filename);
printf("In line %u, the number of columns is %u cols.\n",
rows, cols);
printf("In the previous line it was counted to
%u.\n\nPlease fix this problem now.\n", oldcols);
exit(1);
}
}
}

if (cols != 0 && cols != oldcols) {
printf("ERROR: Line %u (last line) consisted of %u
columns.\nLine %u had %u columns.\n", rows, cols, rows-1,
oldcols);
exit(1);
}

*pRows = rows; /* update results */
*pCols = oldcols;
(*count)++;

printf("Finished reading from file %s.\n\n", filename);
fclose(pFile); /* close input file, finished reading values
in */
}

int countColsInNextLine (FILE *pFile, unsigned *pCols, unsigned
*pRows)
{
int c;
unsigned cols = 0;

c = getc(pFile); /* get first character to start the loop */
do {
testwronginput(c, cols, *pRows);
if (c != EOF && !isspace(c)) { /* first time non-space
encountered, update cols */
cols++;
do { /* skip digits and commas, after first digit
*/
c = getc(pFile);
testwronginput(c, cols, *pRows);
} while (c != EOF && !isspace(c) || c == ',' || c ==
'.');
/* comma should also be valid input in number */
}
while (c != EOF && c != '\n' && isspace(c)) { /* skip
through
blank
spaces, but not '\n' ! */
c = getc(pFile);
testwronginput(c, cols, *pRows);
}
} while (c != EOF && c != '\n'); /* is the line finished or
is EOF
reached? */

*pCols = cols;
return c;
}

void testwronginput(int c, unsigned cols, unsigned rows) /* I
tried isblank() but my system complained about it */
{
if (isalpha(c)) {
printf("Error! Alphabetic character '%c' encountered
before EOF\n", c);
printf("Last succesful location read was: Line %u,
Column %u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see
this error
before the windows shuts down */
exit(1);
}
if (iscntrl(c) && c != 10) {
printf("Error! Control character '%c' encountered before
EOF\n", c);
printf("Last succesful location read was: Line %u,
Column %u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see
this error before the windows shuts down */
exit(1);
}
if (!isprint(c) && c != EOF && c != '\n') {
printf("Error! Non-printing character '%c' encountered
before EOF\n", c);
printf("Last succesful location read was: Line %u,
Column %u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see
this error
before the windows shuts down */
exit(1);
}
}

- - - -- - -- - - - -- - --

Compiler complaints:

int * differes in indirection.... Missing ';' before 'type....


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Mark said:
<snip>

Here's some help. Compile this small program, and run it with the
filename of your .dat file as the command line argument. Try all the
cases you can think of, and see how the error handling works.

Hi Mark,

Thanks a lot for bringing another way of solving this problem... But I
already solved this problem, so imagine changing your program such that
i use malloc to initialize a new 2D array called T_new (untested):


int main(int argc, char *argv[])
{
FILE *fp;
int rows, cols;
enum Error result;
const char *file;
int ret = EXIT_FAILURE;
char buf[8];

/* Open the data file (filename is fixed). */
fp = fopen("testfile.dat", "r");
if(fp == NULL) {
printf("Error: cannot open %s.\n", file);
return ret;
}

/* Try to parse the file, then interpret the result. */
result = parse(fp, &rows, &cols);
if(result != Success) {
printf("Error in input file\n");
exit(1)
}

/* this is the what I want: using number of cols+rows for malloc */
double **T_new = malloc((rows+1)*sizeof(double*));
T_new[0] = malloc((cols*rows)*sizeof(double));

/* test: assuming input file has more than 4 rows and 5 columns */
T_new[4][5] = 431.56;
printf("test-value = %lf", T_new[4][5]");

/* Clean up and exit */
fclose(fp);
return ret;
}

- - - - - - - - - - - -

Since I already solved this problem (and my solution can also take files
with double input elements such as 425,358 or 823.23 as individual
elements, I didn't tested the above)... But you code is really nice to
learn from, and very logically structured. I like that... It gives me
som new ideas for future ways of solving problems.

.... The above is just so you know what I'm asking for, in case you want
to try and solve the problem... I just sended some "ready-to-go
copy/paste code" to Barry Schwarz (18/3-06, time:16:04, but it didn't
show up yet) that show I want to take the result from what corresponds
to your variables called cols and rows, to malloc a 2D-array...


Best regards / Med venlig hilsen
Martin Jørgensen
 
B

Barry Schwarz

Ok, forget everything I wrote earlier... I just need to know how
to fix the following code (3 warnings, 2 errors).

You show exactly two diagnostics at the very bottom of 200 lines of
extremely poorly formatted code. You don't provide the complete
error message and you don't identify to which lines the errors relate.
(or if you did it was buried in your code to the point of
invisibility). You need to give us a fighting chance to help you. Try
all of the following:
Limit your line length so your posting software does not break
things up at an inconvenient place.
Limit your use of vertical white space.
Indent in a very consistent fashion, four characters usually
works well.
- - - -- - -- - - - -- - --
#include <stdlib.h> /* system("PAUSE") */
#include <stdio.h>
#include <stddef.h>
#include <ctype.h> /* for isspace */

/* defintions */
#define max_input_files 3

It is a common convention to code your #define in all caps. Just
something to make it easier to read.
/* more prototypes */
void getdata(char *filename, unsigned *pCols, unsigned *pRows,
int *count);
int countColsInNextLine(FILE *pFile, unsigned *pCols, unsigned
*pRows);
void testwronginput(int c, unsigned cols, unsigned rows);


int main(void)
{
/* read from file and get number of cols+rows */

unsigned count, n_x[max_input_files], n_y[max_input_files];
/* and a lot more var's, not necessary in this example */
double **T, **T_new;

count = 0; /* keep track of number of datafiles read */
getdata("inputfile1.dat", &n_x[0], &n_y[0], &count );
getdata("inputfile2.dat", &n_x[1], &n_y[1], &count );
if(n_x[0] != n_x[1] && n_y[0] != n_y[1])

Did you mean "and" or "or" here? If either mismatches do you quit or
do you quit only if both mismatch?
exit(1);
getdata("inputfile3.dat", &n_x[2], &n_y[2], &count );
if(n_x[1] != n_x[2] && n_y[1] != n_y[2])
exit(1);

double **T = malloc((n_y[0]+1)*sizeof(double*)); /* n_y =
rows */

It will save you problems later on if you use sizeof *T.
double **T_new = malloc((n_y[0]+1)*sizeof(double*)); /* n_y =
rows */

T[0] = malloc((n_x[0]+1)*(n_y[0]+1)*sizeof(double)); /* nx=
cols */

And sizeof *T[0] here.
T_new[0] = malloc((n_x[0]+1)*(n_y[0]+1)*sizeof(double)); /*
nx= cols */

/* eventually test with T[4][6] = 959, and printf("%lf",
T[4][6]); etc... */
}


void getdata(char *filename, unsigned *pCols, unsigned *pRows,
int *count)
{
FILE *pFile;

unsigned rows, cols, oldcols;

printf("Opening file: %s.\n", filename);
if ( (pFile = fopen(filename, "r") ) == NULL)
{
printf("Cannot open file %s.\n", filename);
system("PAUSE"); /* give the user at chance to see this
error
before the windows shuts down */
exit(1);

Use EXIT_FAILURE instead of 1 for portability.
}

*pRows = 0;
*pCols = 0;

/* get nx and ny */
cols = 0;
rows = 0;
if (countColsInNextLine(pFile, &oldcols, &rows) != EOF) { /*
return
oldcols
for first row */

What did that look like on your system????
rows++;
while (countColsInNextLine(pFile, &cols, &rows) != EOF)

Since you increment rows above, did you really intend for function
count... to change its value also? But count... does not change rows.
Why do you define the function to take a pointer when it really wants
the value pointed to?
{ /*

check row 2 -> EOF */
rows++;
if (cols != oldcols) { /* verify that number of cols
didn't
change */

At this point in time (first iteration of while loop), oldcols has not
been initialized.
printf("ERROR: Number of columns is not a
constant in file: %s\n\n", filename);
printf("In line %u, the number of columns is %u cols.\n",
rows, cols);
printf("In the previous line it was counted to
%u.\n\nPlease fix this problem now.\n", oldcols);
exit(1);
}
}
}

if (cols != 0 && cols != oldcols) {
printf("ERROR: Line %u (last line) consisted of %u
columns.\nLine %u had %u columns.\n", rows, cols, rows-1,
oldcols);
exit(1);
}

*pRows = rows; /* update results */
*pCols = oldcols;
(*count)++;

printf("Finished reading from file %s.\n\n", filename);
fclose(pFile); /* close input file, finished reading values
in */
}

int countColsInNextLine (FILE *pFile, unsigned *pCols, unsigned
*pRows)
{
int c;
unsigned cols = 0;

c = getc(pFile); /* get first character to start the loop */
do {
testwronginput(c, cols, *pRows);
if (c != EOF && !isspace(c)) { /* first time non-space
encountered, update cols */
cols++;
do { /* skip digits and commas, after first digit
*/
c = getc(pFile);
testwronginput(c, cols, *pRows);
} while (c != EOF && !isspace(c) || c == ',' || c ==
'.');

Since && has higher precedence that ||, this is treated as
(c != EOF && !isspace(c)) || (c == ',') || (c == '.')
This is an A or B or C expression. If A is true, B and C will never
be evaluated (called a short circuit evaluation). Consider either of
the last two tests. If either is true, is it possible for A to be
false? Obviously not. If A is false, c is either EOF (and B and C
are both false also) or c is whitespace (and B and C are both false
also). The bottom line is that B and C contribute nothing but a
confusion factor. The truth of falseness of the expression is
completely determined by A.
/* comma should also be valid input in number */

Rather than trying to validate a numerical value yourself, you might
consider using strtod to do the work for you. I think it will
properly handle the decimal marker (, or .) based on locale.
}
while (c != EOF && c != '\n' && isspace(c)) { /* skip
through
blank
spaces, but not '\n' ! */
c = getc(pFile);
testwronginput(c, cols, *pRows);
}
} while (c != EOF && c != '\n'); /* is the line finished or
is EOF
reached? */

*pCols = cols;
return c;
}

void testwronginput(int c, unsigned cols, unsigned rows) /* I
tried isblank() but my system complained about it */

There is no isblank. If you want to test for blank, use ' '. If you
want to test for whitespace, use isspace.
{
if (isalpha(c)) {
printf("Error! Alphabetic character '%c' encountered
before EOF\n", c);
printf("Last succesful location read was: Line %u,
Column %u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see
this error
before the windows shuts down */
exit(1);
}
if (iscntrl(c) && c != 10) {

What is 10? It may be \n on your system but it isn't on mine. Don't
use magic ascii codes. Use the escape sequence if you can.
printf("Error! Control character '%c' encountered before
EOF\n", c);

By definition, control character will not print with %c. Use %d so
the user can determine which control character was found.
printf("Last succesful location read was: Line %u,
Column %u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see
this error before the windows shuts down */
exit(1);
}
if (!isprint(c) && c != EOF && c != '\n') {
printf("Error! Non-printing character '%c' encountered
before EOF\n", c);

A non-printing won't display properly with %c. Use %d here also.
printf("Last succesful location read was: Line %u,
Column %u\n", 1+rows, cols);
system("PAUSE"); /* give the user at chance to see
this error
before the windows shuts down */
exit(1);
}
}

- - - -- - -- - - - -- - --

Compiler complaints:

int * differes in indirection.... Missing ';' before 'type....

Sorry, your formatting makes it impossible to compile your code and I
didn't spot these in my review.
Best regards / Med venlig hilsen
Martin Jørgensen


Remove del for email
 
P

Pedro Graca

Martin said:
Ok, forget everything I wrote earlier... I just need to know how
to fix the following code (3 warnings, 2 errors).

I copied lines with problems and inserted a `#ifdef pmg` to the
changed lines. After a few compilation runs gcc output is

$ c90 -Dpmg foo.c
foo.c: In function `countColsInNextLine':
foo.c:135: warning: suggest parentheses around && within ||


if I don't define pmg (so it's the code you posted), gcc output is

$ c90 foo.c
foo.c: In function `main':
foo.c:42: warning: pointer targets in passing arg 4 of `getdata' differ in signedness
foo.c:43: warning: pointer targets in passing arg 4 of `getdata' differ in signedness
foo.c:47: warning: pointer targets in passing arg 4 of `getdata' differ in signedness
foo.c:56: error: redeclaration of `T'
foo.c:39: error: `T' previously declared here
foo.c:56: warning: ISO C89 forbids mixed declarations and code
foo.c:57: error: redeclaration of `T_new'
foo.c:39: error: `T_new' previously declared here
foo.c:39: warning: unused variable `T'
foo.c:39: warning: unused variable `T_new'
foo.c: In function `countColsInNextLine':
foo.c:135: warning: suggest parentheses around && within ||

Will you provide a working email address so that I can
mail you my changes?
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Pedro said:
I copied lines with problems and inserted a `#ifdef pmg` to the
changed lines. After a few compilation runs gcc output is

Ok, but what is pmg?
$ c90 -Dpmg foo.c
foo.c: In function `countColsInNextLine':
foo.c:135: warning: suggest parentheses around && within ||


if I don't define pmg (so it's the code you posted), gcc output is

$ c90 foo.c
foo.c: In function `main':
foo.c:42: warning: pointer targets in passing arg 4 of `getdata' differ in signedness
foo.c:43: warning: pointer targets in passing arg 4 of `getdata' differ in signedness
foo.c:47: warning: pointer targets in passing arg 4 of `getdata' differ in signedness
foo.c:56: error: redeclaration of `T'
foo.c:39: error: `T' previously declared here
foo.c:56: warning: ISO C89 forbids mixed declarations and code
foo.c:57: error: redeclaration of `T_new'
foo.c:39: error: `T_new' previously declared here
foo.c:39: warning: unused variable `T'
foo.c:39: warning: unused variable `T_new'
foo.c: In function `countColsInNextLine':
foo.c:135: warning: suggest parentheses around && within ||

Will you provide a working email address so that I can
mail you my changes?

Sure, or else you could just post it here... But just remove ".spam"
before the @ and remove "spam." after the "@" - that's my e-mail address
(I just did it that way to avoid the spam robots, so please don't post
the full address without "concealment"). At this moment, I don't get
spam to that address and I would like it to be that way, if possible.


Best regards / Med venlig hilsen
Martin Jørgensen
 
M

Mark F. Haigh

Thanks a lot for bringing another way of solving this problem... But I
already solved this problem, so imagine changing your program such that
i use malloc to initialize a new 2D array called T_new (untested):
Since I already solved this problem [...]

I certainly don't think you've solved the problem. In fact, I'm not
even convinced you've managed to state the problem coherently. The
code you've posted thus far is confused, not robust, and
unmaintainable.

Don't be offended. Nobody is born knowing C. You're making a
sustained effort, and that is why we're willing to spend time to help.

There's a lot of things we don't know about what you're trying to do.
But we do know that:

1. You are a student, and this may be a homework assignment. If this
is the case, you're trying to learn how to use C to solve real-world
problems. So we can conclude that you should be working hard to make
your program more clear, robust, and maintainable so that you learn a
lot about C, and as a result, get a good grade.

Or...

2. You are writing a program that you hope others will find useful.
If this is the case, you need to ensure that your program is robust (a
non-robust program is not very useful) and clearly-written and
maintainable (so that other people can understand how the program
works, and can extend it or fix bugs in it).

Either way, you need to work toward the same goals of clarity,
robustness, and maintainability. A solution that does not address all
of these is not a solution at all.
(and my solution can also take files
with double input elements such as 425,358 or 823.23 as individual
elements, I didn't tested the above)... But you code is really nice to
learn from, and very logically structured. I like that... It gives me
som new ideas for future ways of solving problems.

Because you have not assured us that your problem is not homework, I'm
not going to post code that does exactly what you need. It's just a
push in the right direction, and is easily extendable to do exactly
what you need.

Notice that nowhere have you:

1. Described concisely the format of the file you wish to be able to
parse. Do you control the file format? Or is it generated by another
program not under your control?

2. Described what you wish to do with the file. What's the point of
this exercise? What's the big picture? I take it you want to read it
into a multidimensional array so you can manipulate it somehow. What
for?

You have to help us so we can help you. We're not mind readers!

<snip>

Mark F. Haigh
(e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top