hi, wonder if anyone can help me.

I have a text file with the following format:

town_name followed by 12 real numbers i.e

London 7.24 8.15 6.45 3.24 3.66 2.45 4.71 6.78 6.45 8.61 7.45 6.55
Manchester 12.23 10.67 7.56 4.34 5.55 6.29 8.77 14.77 9.77 7.49 8.34 7.66
Liverpool 10.12 6.76 7.87 6.66 4.56 7.82 12.63 9.62 6.02 7.94 8.34 9.18
Bristol 6.55 8.61 4.67 4.86 5.55 2.39 6.66 4.91 2.93 4.66 4.81 7.39
ZZZZZ

the ZZZZZ is a sentinel value which tells my program to stop reading from the file. I need to read the data file and display it in the console window. However I can only get it to work when I have only one number next to the town name, as soon as the others go in, i get strange results. the entire data set needs to be held in an array as I need to do calculations to the data, below is the code I have developed so far...

#include <stdio.h>
#include <string.h>

const int maxrows=12;
const int maxcols=12;
const int maxchar=10;

static char place[maxrows][maxchar];
static char dummy[maxchar];
float rain[maxrows];
float average, annual, wet, dry; 

FILE *fp;

main ()
{
    int i=0;
    if ((fp = fopen("data1.txt", "r"))==NULL)
       printf("Error opening file\n");
    else
    {
        do
        {
            printf("\n");
            fscanf(fp,"%s",&dummy);
            if (strcmp(dummy, "ZZZZZ") !=0)
            {
                strcpy(place[i],dummy);
                fscanf(fp,"%f",&rain[i]);
                printf("%10s\t%2.2f", place[i],rain[i]);
                i++;
            }
        } while ((strcmp(dummy,"ZZZZZ") !=0) and (i<maxrows));
    }
    fclose(fp);
    getchar();
}

thanks in advance

Dani AI

Generated

A common root cause in this thread was loop structure: the program ended up trying to read far more floats than exist on each data line. As and explained, the correct flow is record-oriented — read one town (or one line), then read exactly 12 monthly values for that town — and ’s note about using C’s boolean operator (&&) is important (unless using iso646.h).

A more robust approach is line-based parsing: read each line with fgets, split tokens and convert the first token to the town name and the next up to 12 tokens to numbers. This handles multi-word town names, makes sentinel detection simple (compare the first token to "ZZZZZ"), and gives clearer error handling if tokens are missing or malformed. Example pattern:

/* line-based parsing: first token = town, next tokens = up to 12 numbers */
char line[256];
size_t row = 0;
while (fgets(line, sizeof line, fp) && row < maxrows) {
    line[strcspn(line, "\r\n")] = '\0';
    char *tok = strtok(line, " \t");
    if (!tok) continue;
    if (strcmp(tok, "ZZZZZ") == 0) break;
    strncpy(place[row], tok, maxchar - 1);
    place[row][maxchar - 1] = '\0';
    int col = 0;
    for (tok = strtok(NULL, " \t"); tok && col < maxcols; tok = strtok(NULL, " \t")) {
        char *end; errno = 0;
        double v = strtod(tok, &end);
        if (end == tok || errno == ERANGE) { v = 0.0; } /* handle parse error */
        rain[row][col++] = (float)v;
    }
    /* handle col < maxcols as needed */
    ++row;
}

Practical safety notes: bound string reads (or increase maxchar), always check conversion/scan return values, initialize per-row accumulators before summing, and prefer int main(void) with a return code. Test with deliberately malformed lines and with town names that contain spaces to confirm the chosen parsing strategy behaves as intended.

Recommended Answers

All 9 Replies

Think in terms of rows of records consisting of fields instead of rows and columns:

in = fopen ( "data1.txt", "r" );
if ( in == NULL ) {
  /* Error */
} else {
  int i, j;

  do {
    fscanf ( in, "%s", dummy );
    if ( strcmp ( dummy, "ZZZZZ" ) == 0 )
      break;

    /* Fill the ith record */
    strcpy ( place[i], dummy );
    for ( j = 0; j < max_cols; j++ )
      fscanf ( in, "%f", &rain[i] );

    /* Display the ith record */
    printf ( "%10s\t", place[i] );
    for ( j = 0; j < max_cols; j++ )
      printf ( "%2.2f", rain[i] );
    printf ( "\n" );
  } while ( i < max_rows );
}

First thing I saw was you mixed a little basic with C.

while ((strcmp(dummy,"ZZZZZ") !=0) [b][u]&&[/u][/b] (i<maxrows));

not and. Other than that you were so close. All you needed to do was make another loop inside your do loop

strcpy(place[i],dummy);
 
	for (int x = 0; x < 12; x++) {
		fscanf(fp,"%f",&rain[x]);
		printf("[b]\n\t[/b]%10s\t%2.2f", place[i],rain[x]); }
	i++;

and that solved the problem. I also cleaned up the display a little with the carriage return / tab.

Didn't mean to discredit your response Narue, but it didn't show up until I hit submit.

thanks for your response guys,

I had actually just about figured it out before I read the resonses but they were really helpful, just pushed me in the right direction!

thanks again guys

>First thing I saw was you mixed a little basic with C.
You're gonna love this. :) In C, since the 95 ammendment, the header <iso646.h> defines macros such as and, or, and not_eq as a reasonable alternative to the nasty trigraphs for implementations that don't support the requisite characters to represent the base language. In standard C++ all of those macros are language keywords. So it's not quite a stretch to imagine C or C++ code using them. ;)

can someone have a look at this for me please? i cannot understand why i am getting all the spare 0.00 numbers when i compile!

a text file is required as before, the details are in my first post in this thread

thanks

#include <stdio.h>
#include <string.h>

const int maxrows=12;
const int maxcols=12;
const int maxchar=10;

static char place[maxrows][maxchar];
static char dummy[maxchar];
float rain[maxrows][maxcols];
float average, annual, wet, dry; 

FILE *fp;

main ()
{
    int x=0;
    if ((fp = fopen("data1.txt", "r"))==NULL)
       printf("Error opening file\n");
    else
    {
        do
        {
            printf("\n\n");
            fscanf(fp,"%s",&dummy);
            if (strcmp(dummy, "ZZZZZ") !=0)
            {
                strcpy(place[x],dummy);
                printf("%10s", place[x]);
                annual=0;
                for (int i=0; i<maxrows; i++) 
                {
                    for(int j=0; j<maxcols; j++)
                    {
                        fscanf(fp,"%f",&rain[i][j]);
	                    printf("\t%2.2f",rain[i][j]); 
	                    annual=annual+rain[i][j];
                    }    
	             }printf("\tAnnual rainfall is %3.2f", annual);
	             x++;
            }
        } while ((strcmp(dummy,"ZZZZZ") !=0) && (x<maxrows));
    }
    fclose(fp);
    getchar();
}

never mind, its sussed now, was a simple error on my part!!

Your nested for loops mean that you are trying to read 144 values each line. To me it looks like the do...while is attempting to be what the first for loop should be: rows. I'd do something more like this.

for ( int i = 0; i < maxrows; ++i )
      {
         fscanf ( fp,"%s", place[i] );
         if ( strcmp ( place[i], "ZZZZZ" ) == 0 )
         {
            break;
         }
         printf ( "%10s", place[i] );

         annual = 0;
         for ( int j = 0; j < maxcols; ++j )
         {
            fscanf ( fp, "%f", &rain[i][j] );
            printf ( "\t%2.2f", rain[i][j] );
            annual = annual + rain[i][j];
         }
         printf("\tAnnual rainfall is %3.2f\n", annual);
      }

Unless the format of your file has changed, you're trying to read too many floats, and fscanf is failing miserably when you get to the next city. Here's how any logic you use should work:

for each line
  read the name
  read 12 floats

Anything else will give you incorrect output. As it is, your code is trying to do this:

for each line
  read the name
  read 144 floats

Notice the difference?

yes, i figured it out now, i realised that it was trying to read in far too many values but it is working fine now..

thanks again

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.