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

C

CBFalconer

Barry said:
. snip ...

There is no isblank. If you want to test for blank, use ' '.
If you want to test for whitespace, use isspace.

Yes there is, in C99. From N1124 (missing in N869):

7.4.1.3 The isblank function

Synopsis

1 #include <ctype.h>

int isblank(int c);

Description

2 The isblank function tests for any character that is a
standard blank character or is one of a locale-specific set
of characters for which isspace is true and that is used to
separate words within a line of text. The standard blank
characters are the following:

space (' '), and horizontal tab ('\t').

In the "C" locale, isblank returns true only for the standard
blank characters.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
?

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

Barry said:
You show exactly two diagnostics at the very bottom of 200 lines of
extremely poorly formatted code. You don't provide the complete

Just look what's inside main().
error message and you don't identify to which lines the errors relate.

Well, I can't imagine it is so difficult to copy/paste the code and see
for yourself. I also didn't know that outlook apparently screwed up the
formatting again, since I haven't posted that many posts in this group,
as I'm still learning the C-language. Still it should just be a few
lines where you remove the extra return that outlook inserted.
(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.

I've heard that before. And now I think that's a stupid advice. The
point is that I *shouldn't* limit the line length because then you get
these errors that you're complaining about here. Your news reader should
just wrap the lines if they're too long.
Limit your use of vertical white space.
Indent in a very consistent fashion, four characters usually
works well.

This *IS* 4 characters.
- - - -- - -- - - - -- - --
#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.
Ok.
/* 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?

Sorry, I meant "or", but that's not the important thing here.
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.

Ok, thanks.
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.
Yes.
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.

Ok, but still that's not the important thing here.
What did that look like on your system????

It looked fine until I saw your reply.
Since you increment rows above, did you really intend for function
count... to change its value also? But count... does not change rows.

Why are you talking about the "count" variable in those two lines? If
you want, you can go back to message-ID <[email protected]> and
run the code from there. Still, this is not the relevant part, and the
above should be okay - at least it has worked before.
Why do you define the function to take a pointer when it really wants
the value pointed to?

Because it needs to change the values. If you want to make it another
way, that's fine but not the most important thing here since the code
worked before (see message-ID shown before).
At this point in time (first iteration of while loop), oldcols has not
been initialized.

Wrong. It was initialized just before that, here:

if (countColsInNextLine(pFile, &oldcols, &rows) != EOF)

But still, that is not relevant. What is relevant, is that I would like
the code to compile.
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

Damn, you're right. I think there's something wrong there... Perhaps it
should rather be while (c != EOF || isspace(c) || c == ',' || c == '.');
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.




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.

Sure it will? Still, not so important since the code worked in the
message-ID I gave you earlier in this post.
There is no isblank. If you want to test for blank, use ' '. If you
want to test for whitespace, use isspace.

Well, there is on p.229 in "C primer plus". But not on my system.
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.

Ok. I'll see if I can remember it. I just saw in the debugger that I
think scanf left a 10 in the buffer and if I didn't put this here, it
would have taken that as a control character and stop the program.
By definition, control character will not print with %c. Use %d so
the user can determine which control character was found.

Ok, still not important.
A non-printing won't display properly with %c. Use %d here also.

Ok, still not important to me.
Sorry, your formatting makes it impossible to compile your code and I
didn't spot these in my review.

I'll post the code again so you should just copy/paste and this time I
copy/paste the code to my macintosh computer and post it from
Thunderbird instead of outlook. I think that'll have this effect that
the lines will not be broken stupid places and then your compiler should
get about the same errors and warnings as me I hope.


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

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

Barry said:
On Sat, 18 Mar 2006 16:04:24 +0100, "Martin Joergensen"

Sorry, your formatting makes it impossible to compile your code and I
didn't spot these in my review.

Okay, forget about this wrapping thing. Guess you're right. I just can't
restrict Visual studio from making lines longer than 65 characters or
so. I went through all the options and help. The following should be
better in that I don't think it inserts ekstra linebreaks in places
never intended to have linebreaks. So what's important is what's inside
main() and I hope that copy/pasting should work - I manually fixed some
comments etc.

- - - - - -- - - - -- -
#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 */
}



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);
/* give the user at chance to see this error before the windows
shuts down */
system("PAUSE");
exit(1);
}

*pRows = 0;
*pCols = 0;

/* get nx and ny */
cols = 0;
rows = 0;
/* return oldcols for first row */
if (countColsInNextLine(pFile, &oldcols, &rows) != EOF) {
rows++;
/* check row 2 -> EOF */
while (countColsInNextLine(pFile, &cols, &rows) != EOF) {
rows++;
/* verify that number of cols didn't change */
if (cols != oldcols) {
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.\n");
printf("Line %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);
/* first time non-space encountered, update cols */
if (c != EOF && !isspace(c)) {
cols++;
/* skip digits and commas, after first digit */
do {
c = getc(pFile);
testwronginput(c, cols, *pRows);
} while (c != EOF || isspace(c) || c == ',' || c == '.');
/* comma should also be valid input in number */
}
/* skip through blank spaces, but not '\n' ! */
while (c != EOF && c != '\n' && isspace(c)) {
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);
/* give the user at chance to see this error before the windows
shuts down */
system("PAUSE");
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);
/* give the user at chance to see this error before the windows
shuts down */
system("PAUSE");
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);
/* give the user at chance to see this error before the windows
shuts down */
system("PAUSE");
exit(1);
}
}

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


Best regards / Med venlig hilsen
Martin Jørgensen
 
P

Pedro Graca

Martin said:
Ok, but what is pmg?

Just my initials. I use them to easily identify changes I make to code.

#ifdef pmg
int main(void)
#else
void main()
#endif

or

int main(void) /* pmg: was void main() */
Will you provide a working email address so that I can
mail you my changes?

[...] or else you could just post it here...


.... I'll post the snippets I changed ...

// ...

/* more prototypes */
#ifdef pmg
void getdata(char *filename, unsigned *pCols, unsigned *pRows, unsigned *count);
#else
void getdata(char *filename, unsigned *pCols, unsigned *pRows, int *count);
#endif

// ...

#ifdef pmg
T = malloc((n_y[0]+1) * sizeof *T); /* n_y = rows */
T_new = malloc((n_y[0]+1) * sizeof *T_new); /* n_y = rows */
#else
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 */
#endif
#ifdef pmg
T[0] = malloc((n_x[0]+1)*(n_y[0]+1) * sizeof *T[0]); /* nx= cols */
T_new[0] = malloc((n_x[0]+1)*(n_y[0]+1) * sizeof *T[0]); /* nx= cols */
#else
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 */
#endif
/* eventually test with T[4][6] = 959, and printf("%lf", T[4][6]); etc... */
#ifdef pmg
return 0;
#else
#endif
}

#ifdef pmg
void getdata(char *filename, unsigned *pCols, unsigned *pRows, unsigned *count) {
#else
void getdata(char *filename, unsigned *pCols, unsigned *pRows, int *count) {
#endif

// ...
just remove ".spam"
before the @ and remove "spam." after the "@" - that's my e-mail address
At this moment, I don't get
spam to that address and I would like it to be that way, if possible.

I sent the full code to your email address. Please excuse me for asking
for the email address; somehow it never occurred to me to remove the
spams from the address you use and try that.
 
C

CBFalconer

Martin said:
Just look what's inside main().


Well, I can't imagine it is so difficult to copy/paste the code
and see for yourself. I also didn't know that outlook apparently
screwed up the formatting again, since I haven't posted that many
posts in this group, as I'm still learning the C-language. Still
it should just be a few lines where you remove the extra return
that outlook inserted.

If (you can't go to the trouble of making your posts easily
readable and usable, by doing such things as proper code
indentation, using spaces in place of tabs, restricting line length
to about 65 (maybe 72), using /**/ comments only) THEN:

we can't be bothered reading it.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
K

Keith Thompson

Martin Jørgensen said:
Barry Schwarz wrote: [...]
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.

I've heard that before. And now I think that's a stupid advice. The
point is that I *shouldn't* limit the line length because then you get
these errors that you're complaining about here. Your news reader
should just wrap the lines if they're too long.

That's the problem. If you post code with very long lines, some
software somewhere between your computer and mine is likely to wrap
the lines. If a line is wrapped in the middle of a string literal,
the result will not compile.

Keep any code you post below 72 columns. Use only spaces, not tabs.

And be very careful throwing around words like "stupid".
 
?

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

Keith said:
Martin Jørgensen said:
Barry Schwarz wrote:
[...]
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.

I've heard that before. And now I think that's a stupid advice. The
point is that I *shouldn't* limit the line length because then you get
these errors that you're complaining about here. Your news reader
should just wrap the lines if they're too long.


That's the problem. If you post code with very long lines, some
software somewhere between your computer and mine is likely to wrap
the lines. If a line is wrapped in the middle of a string literal,
the result will not compile.

Keep any code you post below 72 columns. Use only spaces, not tabs.

And be very careful throwing around words like "stupid".

The problem is that if I force outlook to make a new line after 72
columns, you will be having a *much* harder time reading the code. I
still don't know how and if possible to make visual studio restrict
itself to whatever columns. I couldn't find anything in options.


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

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

Mark said:
Martin Jørgensen wrote:

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.

Last time I tried it worked.
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.

It is not a homework assignment.
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.




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.

It is not a homework assignment.
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?

I did that already in the beginning of the thread:
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

You can replace some of them with decimal numbers if you don't trust me.
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!

I already told that a couple of times: Now I want to get number of rows
and number of cols for malloc'ing a 2D-array. You don't have to be a
mind reader to understand that. I wrote that a couple of times since
<[email protected]> and I even posted a program that just don't
compile in <[email protected]> and I don't know why. So if
there's any problem in answering this question, the reason is not that
you aren't a mind reader.


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

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

Pedro said:
Martin Jørgensen wrote: -snip-

... I'll post the snippets I changed ...
Thanks.

// ...

/* more prototypes */
#ifdef pmg
void getdata(char *filename, unsigned *pCols, unsigned *pRows, unsigned *count);
#else
void getdata(char *filename, unsigned *pCols, unsigned *pRows, int *count);
#endif

Yeah... That should ofcourse give a warning...
// ...

#ifdef pmg
T = malloc((n_y[0]+1) * sizeof *T); /* n_y = rows */
T_new = malloc((n_y[0]+1) * sizeof *T_new); /* n_y = rows */
#else
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 */
#endif

I should just not have used double **T, etc.
#ifdef pmg
T[0] = malloc((n_x[0]+1)*(n_y[0]+1) * sizeof *T[0]); /* nx= cols */
T_new[0] = malloc((n_x[0]+1)*(n_y[0]+1) * sizeof *T[0]); /* nx= cols */
#else
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 */
#endif

I see. Not critical though, I guess - but nicer.
/* eventually test with T[4][6] = 959, and printf("%lf", T[4][6]); etc... */
#ifdef pmg
return 0;
#else
#endif
}

#ifdef pmg
void getdata(char *filename, unsigned *pCols, unsigned *pRows, unsigned *count) {
#else
void getdata(char *filename, unsigned *pCols, unsigned *pRows, int *count) {
#endif
-snip-

Thanks a lot... It seems to work!

The most critical thing must have been that I used double **T = ...
instead of just T = malloc... I wouldn't have figured that out myself
since I haven't worked that much with malloc. What's the difference
anyway, just to point it completely out?

So close still... Thanks a lot - I appreciate your help. I hope that I
can figure the rest of the implementation out in my bigger program
myself, from this piece of code.


Best regards / Med venlig hilsen
Martin Jørgensen
 
C

CBFalconer

Martin said:
Keith Thompson wrote:
.... snip ...

The problem is that if I force outlook to make a new line after 72
columns, you will be having a *much* harder time reading the code. I
still don't know how and if possible to make visual studio restrict
itself to whatever columns. I couldn't find anything in options.

You don't need to use such stupid software as Outhouse. There are
many available decent newsreaders. As far as the VS editor is
concerned, you should be capable of hitting the return (enter) key
at the end of code lines. There is almost never any need for lines
of over 72 chars length. C has some useful provisions, such as
concatenating adjacent strings, or continuation lines, in the rare
case.

You can also fix your source with indent. The following line will
wrap, but will keep code lines suitably short.

-kr -l66 -i3 -bad -di16 -lc66 -nce -ncs -cbi0 -bbo -pmt -psl -ts1
-cdw

That could be the content of indent.pro on your windoze machine,
and will configure indent 2.2.9. Note the -l66, which sets the
right margin, while -i3 sets indentation.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
C

CBFalconer

Martin said:
Barry Schwarz wrote:

-snip-


Okay, forget about this wrapping thing. Guess you're right. I
just can't restrict Visual studio from making lines longer than
65 characters or so. I went through all the options and help. The
following should be better in that I don't think it inserts
ekstra linebreaks in places never intended to have linebreaks. So
what's important is what's inside main() and I hope that
copy/pasting should work - I manually fixed some comments etc.
.... snip ...

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);
/* give the user at chance to see this error before the windows
shuts down */
system("PAUSE");
exit(1);
}

As an example, lets just deal with the above extract, and see a
reasonable way to format it that will work everywhere.

void getdata(char *filename, /* room to describe */
unsigned *pCols, /* the various parameters */
unsigned *pRows, /* if desired */
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);

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

And, instead of the very questionable use of system("PAUSE") etc.,
I would use:

printf("Cannot open file %s.\n"
"Hit <enter> to continue",
filename);
fflush(stdout);

/* give the user at chance to see this error */
/* before the windows shuts down */
getchar();
exit(EXIT_FAILURE);
}

Note the use of string concatenation to avoid long lines, and
simultaneously provide an image of the output screen in the source
code. Now that portion is also portable. You can also easily
change to using fprintf(stderr, "..., which is a preferable place
for error messages.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
C

CBFalconer

Martin said:
Mark F. Haigh wrote:
.... snip ...

I already told that a couple of times: Now I want to get number of
rows and number of cols for malloc'ing a 2D-array. You don't have
to be a mind reader to understand that. I wrote that a couple of
times since <[email protected]> and I even posted a
program that just don't compile in <[email protected]> and
I don't know why. So if there's any problem in answering this
question, the reason is not that you aren't a mind reader.

Now don't get all snippy with your panties in a knot, or you will
find your help rapidly disappears. We all have better things to do
than laboriously research a thread. Articles should stand by
themselves, and if something is unclear just explain it. Articles
should also be short.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
M

Mark F. Haigh

Martin said:
Mark said:
Martin Jørgensen wrote:

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.

Last time I tried it worked.

It may "work", but it's certainly a childish effort, at best. Let me
guess, you're a first year student? Your code sucks. Unclear,
unmaintainable, unportable. Amateur.

It is not a homework assignment.
It is not a homework assignment.

Very cute. I'm impressed. I think all of us are.
I did that already in the beginning of the thread:


You can replace some of them with decimal numbers if you don't trust me.


I already told that a couple of times: Now I want to get number of rows
and number of cols for malloc'ing a 2D-array. You don't have to be a
mind reader to understand that. I wrote that a couple of times since
<[email protected]> and I even posted a program that just don't
compile in <[email protected]> and I don't know why.

We all know why it doesn't compile. It's because you don't know what
you're talking about. Your code sucks. Most regulars here can write
the complete program you've been struggling with for 3 days in about 10
minutes.
So if
there's any problem in answering this question, the reason is not that
you aren't a mind reader.

**** off. You are quite possibly the most worthless programmer (and
human being) I've ever seen. You'll get no further responses.

I have better things to do than waste my time dealing with morons like
you.


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

Vladimir S. Oka

Mark F. Haigh opined:
Martin said:
Mark said:
Martin Jørgensen wrote:

<snip>

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):


<code snipped>

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.

Last time I tried it worked.

It may "work", but it's certainly a childish effort, at best. Let me
guess, you're a first year student? Your code sucks. Unclear,
unmaintainable, unportable. Amateur.

So? He's at least trying, unlike many other we see here. Since when has
being a beginner become shameful?
Very cute. I'm impressed. I think all of us are.

This is devoid of content (scorn is not content).

said:
We all know why it doesn't compile.

So why not tell him?
It's because you don't know what
you're talking about. Your code sucks.

Maybe, but if he's really a beginner it's not a sin.
Most regulars here can write
the complete program you've been struggling with for 3 days in about
10 minutes.

Maybe, but how does it help the OP, or anybody else?
**** off. You are quite possibly the most worthless programmer (and
human being) I've ever seen. You'll get no further responses.

I have better things to do than waste my time dealing with morons
like you.

And this is completely unacceptable.

I, for one, will be quite happy if you did not contribute here any
further.

*PLONK*

PS
You also snipped quite a lot of OPs post which very politely expresses
gratitude for your help, so there's really no reason for you to be as
rude and scornful as you were.
 
J

Joe Wright

Martin said:
Keith Thompson wrote: [ snip ]
That's the problem. If you post code with very long lines, some
software somewhere between your computer and mine is likely to wrap
the lines. If a line is wrapped in the middle of a string literal,
the result will not compile.

Keep any code you post below 72 columns. Use only spaces, not tabs.

And be very careful throwing around words like "stupid".

The problem is that if I force outlook to make a new line after 72
columns, you will be having a *much* harder time reading the code. I
still don't know how and if possible to make visual studio restrict
itself to whatever columns. I couldn't find anything in options.


Best regards / Med venlig hilsen
Martin Jørgensen
Martin, you are making excuses instead of solving problems. That you
don't know how to do it right is not a good reason to keep on doing it
wrong.

Outlook is not the only or even the preferable news client. There's
Thunderbird, Free Agent, etc. Look 'em up.

I don't know either how to make the VS editors emit spaces instead of
tabs (Anybody else know?). But in preparing a code snippet to be
included in a usenet post I will run it through GNU indent to remove
tabs and indent to 3 spaces.

If you can't be bothered to prepare your code for us, don't be surprised
if we are not prepared to even read what you offer.
 
R

Richard G. Riley

Michael Mair wrote:
-snip-


Do you like my new program?

I find it *REALLY* useful :)

Hi Martin,

I think you need to take a step back and consider making it about
1/3rd of the size and 100 times more readable. I really believe you
have overcomplicated this : as a result of you learning C as you go I suspect.

Some hints:

1) create a struct for representing rows & column count - then have an
array of these. all this n_x and n_y is not nice on the eye. And be
concistent in your naming conventions. "y" is not a proper
alternative for "number of columns".
2) Consider reading in the data a line at the time using fscanf/fgets or
something. Reading in by character is often inefficient.
3) What is "count" and why are you passing a reference to it when the
function always increments it? Sloppy. Return a success/fail code.
4) never call a function "getdata" and especially never make such a
function a void IMO : return a success code or a count or a pointer
to a result of interest.
5) stop exiting from the lower level funtions. If you *must* have a
function called "testwronginput" return a success code and
certainly do not pass in pointers to column & row data : it doesnt
need to know about them - it should only be interested in the
character it is checking. You have complicated this function and
made it heavy on the eye. Keep it simple.
6) I'm always suspicous of anything which counts anything in a "next"
line. It should be counting things in "current" line. Whenever I
see two calls to something like "countColsInNextLine" next to each
other I have to wonder if there is a better, clearer way to handle
it. Often turning the loop upside down works.
7) comment your functions : good clear C is self explanatory
manytimes, unfortunately functions like "testwronginput" are far
from clear - it seems an almost arbitrary attack on various forms
of white space etc. Hence a spec would be appreciated.

Finally : use google. I googled "reading lines in from file in c" ...

http://www.mrx.net/c/program.html

fgets might be helpful. fcanf even more so for a strict input
format. How "strict" is your input detail? Maybe its ok to assume the
format is rigid?

It is still far from clear what format the data file is in. Explain
this clearly in words - not as a c comment.

good luck!

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

#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
 
P

Pedro Graca

Martin said:
The most critical thing must have been that I used double **T = ...
instead of just T = malloc... I wouldn't have figured that out myself
since I haven't worked that much with malloc. What's the difference
anyway, just to point it completely out?

When you have an array of arrays dynamically allocated
(eg double ** table;) you /first/ have to allocate the rows, and then
/for each row/ allocate the columns;

#include <stdlib.h>

#define NUM_ROWS 10
#define NUM_COLS 12

int main(void) {
size_t i;
double ** table;

/* allocate space for NUM_ROWS * NUM_COLS elements */

/* first the rows */
table = malloc(NUM_ROWS * sizeof *table);
if (!table) {
fprintf(stderr, "Not enough memory. Program aborted.\n")
exit(EXIT_FAILURE);
}

/* and then the columns */
for (i = 0; i < NUM_ROWS; ++i) {
table = malloc(NUM_COLS * sizeof *(table));
if (!table) {
if (i > 0) {
/* release previously allocated memory */
size_t j;
/* NOTE: as j is size_t (some kind of unsigned int)
* `--j` is perfectly defined and will not break */
for (j = i-1; j < i; --j) {
free(table[j]);
}
}
free(table);
fprintf(stderr, "Not enough memory. Program aborted.\n")
exit(EXIT_FAILURE);
}
}

/* work with table */

/* release memory in reverse order: first the columns */
for (i=0; i<NUM_ROWS; ++i) {
free(table);
}
/* and then the rows */
free(table);

return 0;
}
 
?

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

Joe said:
Martin said:
Keith Thompson wrote:

[ snip ]
The problem is that if I force outlook to make a new line after 72
columns, you will be having a *much* harder time reading the code. I
still don't know how and if possible to make visual studio restrict
itself to whatever columns. I couldn't find anything in options.


Best regards / Med venlig hilsen
Martin Jørgensen
Martin, you are making excuses instead of solving problems. That you
don't know how to do it right is not a good reason to keep on doing it
wrong.

Outlook is not the only or even the preferable news client. There's
Thunderbird, Free Agent, etc. Look 'em up.

I don't know either how to make the VS editors emit spaces instead of
tabs (Anybody else know?). But in preparing a code snippet to be
included in a usenet post I will run it through GNU indent to remove
tabs and indent to 3 spaces.

If you can't be bothered to prepare your code for us, don't be surprised
if we are not prepared to even read what you offer.

Don't be surprised if new users in this group don't know how to prepare
the code for you. It really has a obvious reason, believe it or not. As
somebody else wrote, I'm not a mind-reader too.


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

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

CBFalconer said:
... snip ...



You don't need to use such stupid software as Outhouse. There are
many available decent newsreaders. As far as the VS editor is
concerned, you should be capable of hitting the return (enter) key
at the end of code lines. There is almost never any need for lines
of over 72 chars length. C has some useful provisions, such as
concatenating adjacent strings, or continuation lines, in the rare
case.

You can also fix your source with indent. The following line will
wrap, but will keep code lines suitably short.

-kr -l66 -i3 -bad -di16 -lc66 -nce -ncs -cbi0 -bbo -pmt -psl -ts1
-cdw

That could be the content of indent.pro on your windoze machine,
and will configure indent 2.2.9. Note the -l66, which sets the
right margin, while -i3 sets indentation.

I will take a look at that.


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

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

Pedro said:
When you have an array of arrays dynamically allocated
(eg double ** table;) you /first/ have to allocate the rows, and then
/for each row/ allocate the columns;

Yeah, I have that under control... I think I can figure out the rest myself.
#include <stdlib.h>

#define NUM_ROWS 10
#define NUM_COLS 12

int main(void) {
size_t i;
double ** table;

/* allocate space for NUM_ROWS * NUM_COLS elements */

/* first the rows */
table = malloc(NUM_ROWS * sizeof *table);
if (!table) {
fprintf(stderr, "Not enough memory. Program aborted.\n")
exit(EXIT_FAILURE);
}

/* and then the columns */
for (i = 0; i < NUM_ROWS; ++i) {
table = malloc(NUM_COLS * sizeof *(table));
if (!table) {
if (i > 0) {
/* release previously allocated memory */
size_t j;
/* NOTE: as j is size_t (some kind of unsigned int)
* `--j` is perfectly defined and will not break */
for (j = i-1; j < i; --j) {
free(table[j]);
}
}
free(table);
fprintf(stderr, "Not enough memory. Program aborted.\n")
exit(EXIT_FAILURE);
}
}

/* work with table */

/* release memory in reverse order: first the columns */
for (i=0; i<NUM_ROWS; ++i) {
free(table);
}
/* and then the rows */
free(table);

return 0;
}


I'll take a closer look later. Thanks again.


Best regards / Med venlig hilsen
Martin Jørgensen
 

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

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top