0

Sorry, but I know how to do it in other languages, but C is rather new to me. I need to import an ascii grid file in a C code. The structure of the file is as follows:

ncols 12
nrows 101
xllcorner 2.0830078125
yllcorner 39.35908297583665
cellsize 0.00439453125
nodata_value -2147483648
401.99 407.38 394.17 362.35 342.36 335.13 319.91 284.99 262.88 259.58 245.62 233.58
397.63 396.36 380.70 358.96 339.35 327.96 314.06 296.73 279.11 264.80 257.20 249.97
389.71 381.29 356.41 338.75 326.04 323.36 317.67 301.30 281.79 269.46 261.94 250.72
.....

I can read the bulk of values but I am struggling to properly import the first 6 lines in two arrays, a character one (namevar) and a double one (valvar). My only partially working code is:

#define ny      101
#define nx      12
#define dime    nx *ny
int main(void)
{
    FILE   *dem;
    double Z[dime], varval[6];

    char namevar[12];
    int  l = 1;

    dem = fopen("buttami.txt", "r");
    int i;
    int j;

    while (l < 7)
    {
        //
        fscanf(dem, "%s %f\n", &namevar, &varval[l]);
        printf("%s %.8f\n", namevar, varval[l]);

        l++;
    }
    for (i = 1; i < dime; i++)
    {
        fscanf(dem, "%lf", &Z[i]);
        printf("%.5f ", Z[i]);

        printf("\n");
    }

    fclose(dem);
}
harper
  • 13,345
  • 8
  • 56
  • 105
  • 1
    Welcome to SO. Please apply proper formatting. Especially proper indentation is important for readability. Also pelase provide a [MCVE](https://stackoverflow.com/help/mcve). Your code is not compileable – Gerhardh Aug 01 '22 at 11:15
  • 2
    You have no error checking. What happens if the file fail to open? Also, remember that the size you use when declaring arrays is the number of elements, not top index, and that array indexes are zero-based. Your array `varval` will have indexes from `0` to `5`, while you're looping from `1` to `6`. – Some programmer dude Aug 01 '22 at 11:15
  • Once you get this working, remember to change the line `for(i = 0; i < dime; i++)` so that it instead uses the actual `nrows` and `ncols` values read from the file! – Steve Summit Aug 01 '22 at 11:26
  • Remove the `\n` from `fscanf()` format string. Please see [What is the effect of trailing white space in a scanf() format string?](https://stackoverflow.com/questions/19499060/what-is-the-effect-of-trailing-white-space-in-a-scanf-format-string) You should aim at removing *leading* whitespace but that's done automatically by `%s` and `%f`. – Weather Vane Aug 01 '22 at 11:46
  • `fscanf(dem,"%s %f\n",&namevar,&varval[l]);`First, `namevar` is an array that already decays to a pointer. No need to add a `&` here. Second, `varval` is an array of `double`. That means you must use `%lf` as format specifier. Third, you should always check return value of all IO function calls. Forth, illegal index `6` while range is `0..5` (was already mentioned before.) – Gerhardh Aug 01 '22 at 12:10
  • 2
    *Always a bug*: not testing the return value from fscanf(). – Jens Aug 01 '22 at 13:22
  • Using floating point variables to hold exact values, like number of lines/columns, is not recommended. – HAL9000 Aug 01 '22 at 14:44
  • Once you get this preliminary version working, you will want to make your keyword/value code more general. You will want to allow for more than 6 keyword/value pairs, and you'll want to allow for reading them in any order — that is, you'll want to pay attention to the keyword values, and not assume (as you do here) that `varval[4]` will always be the cell size. – Steve Summit Aug 01 '22 at 15:00

2 Answers2

0

Comments address many issue, this focuses on your specific mention...

"I am struggling to properly import the first 6 lines in two arrays, a character one (namevar) and a double one (valvar)"

First, the variable char namevar[12]; is too small to contain the longest name string it will need to contain: "nodata_value" as stored in the file contains 12 characters requiring the variable namevar to be created with size of at least 13 to provide room for the null terminator. ( see definition of C string )

The top part of the input file could be thought of as a header section, and its content as tag/values. An array of struct is useful to store content of varying types into a single array, each containing a set of members to accommodate the various types, in this case one C string, and one double. For example:

#define NUM_HDR_FLDS 6 // to eliminate magic number '6' in code below

typedef struct {
   char namevar[20];
   double varval;
} header_s;

header_s header[NUM_HDR_FLDS] = {0};//array of NUM_HDR_FLDS elements, each contains two members,
                         //1 a char array with room for null terminator for field name
                         //2 a double to contain value

Then your fscanf() loop will look like this:

     //note changes to format specifier and the 
     //string member needs no &  
     int l=0;//C uses zero base indexing
     dem=fopen("buttami.txt", "r");
     if(dem)//test for success before using
     {
         while(l<NUM_HDR_FLDS){//zero base indexing again (0-5)
             if(fscanf(dem,"%s %lf", header[l].namevar,&header[l].varval) == 2)
             {
                 printf("%s %.8f\n",header[l].namevar,header[l].varval);
             } //else handle error
             l++;
         }
         fclose(dem);
     }
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • based on the very prompt and precise suggestions, I modified my code, which is now working properly, allowing me to easily import and edit an ascii grid format with the elevations in a single vector. If needed I can post or provide the resulting code. Thanks a lot! – tiziano vittori Aug 02 '22 at 12:03
0

By your example data description, I guess it is Arc/Info Ascii Grid foramt by wikipedia https://en.wikipedia.org/wiki/Esri_grid.

For raster data files I/O, please try library Gdal. Gdal doc about this format https://gdal.org/drivers/raster/aaigrid.html

Here is code samples for open and read a raster file https://gdal.org/tutorials/raster_api_tut.html

g11de
  • 74
  • 5