Thread: Reading values from file to first 2 columns of 2d array, assigning 0 to 3rd column

  1. #1
    Registered User
    Join Date
    Apr 2014
    Posts
    6

    Reading values from file to first 2 columns of 2d array, assigning 0 to 3rd column

    Hi guys,

    Hoping someone can clarify where I am in error. I am attempting to read values from a file into a 2d array temp[31][2] (31 rows, 3 columns)

    I only want the values from the file to be read into the first two columns.

    I believe I am accomplishing that but when I go to print the array, I expect the first two columns to have the file data and the third column to have all zeros. The third column, however is printing such that the value is the next row/first column.

    iE: I'm not sure for instance why on the bottom loop for line 1 it doesn't print:

    temp[0][0] temp[0][1] temp[0][2]

    20 49 0


    It instead prints:
    20 49 1

    Can anyone shed some light on what I am doing incorrectly here? Thank you!

    Code:
    #include <stdio.h>
    Code:
    #include <math.h>
    FILE *inptr;
    
    
    int main()
    {
    	int temp[31][2] = {0}, tempavg[31][2] = {0};
    	int i, j, k, sum;
    	inptr = fopen("ProgrammingProject14.txt", "r");
    	
    	//Following code reads in values to temp[][] from file ProgrammingProject14.txt:
    	for (i = 0; i < 31; i++)
    	{
    		for (j = 0; j < 2; j++)
    		{
    			fscanf(inptr, "%d", &temp[i][j]);
    		}
    	}
    	fclose(inptr);
    	
    	//Following code prints 2d array temp[]:
    	printf("Low\tHigh\tAverage\n");
    	for (i = 0; i < 31; i++)
    	{
    		for(j = 0; j < 3; j++)
    		{
    			printf("%d\t", temp[i][j]);
    		}
    	printf("\n");
    	}
    	
    //	printf("Low\tHigh\tAverage\n");
    //	for (i = 0; i < 31; i++)
    //	{
    //		for(j = 0; j < 3; j++)
    //		{
    //			printf("%d\t", tempavg[i][j]);
    //		}
    //	printf("\n");
    //	}
    	
    	return 0;
    }
    


    Contents of ProgrammingProject14.txt:

    20 49 1 20 8 26 12 49 23 51 26 55 22 60 35 57 28 58 40 74 36 77 28 76 48 70 47 70 31 67 25 46 22 46 32 47 33 48 40 72 32 67 27 44 29 47 35 46 42 64 43 70 44 65 35 54 42 84 44 73 44 86



  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Hoping someone can clarify where I am in error. I am attempting to read values from a file into a 2d array temp[31][2] (31 rows, 3 columns)
    That's actually 31 rows by 2 columns. Remember arrays start at zero and end at size - 1 so your array would have legal indexes of 0 and 1.

    Jim

  3. #3
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Code:
    int temp[31][2] = {0}, tempavg[31][2] = {0};
    How many columns do temp and tempavg have?

    Note, you really, really should have constants for these numbers. It would help you avoid such mistakes
    Code:
    #define NUM_ROWS 31
    #define NUM_COLS 3
    int temp[NUM_ROWS][NUM_COLS]...
    
    for (r = 0; r < NUM_ROWS; r++) {
        for (c = 0; c < NUM_COLS; c++) {  // use NUM_COLS-1 if you want to skip the last column
    Reads much better, and much easier if you ever want to change number of rows/columns.

  4. #4
    Registered User
    Join Date
    Apr 2014
    Posts
    6
    Quote Originally Posted by jimblumberg View Post
    That's actually 31 rows by 2 columns. Remember arrays start at zero and end at size - 1 so your array would have legal indexes of 0 and 1.

    Jim
    I feel so dumb. For some reason I had in my head that by defining is as temp[31][2], that meant the columns would be 0, 1 and 2. Rather than 2 columns. I changed
    Code:
    int temp[31][3] = {0}
    and it works fine now.

    Thank you for the quick response. I can't believe i just wasted hours trying to figure that out.

  5. #5
    Registered User
    Join Date
    Apr 2014
    Posts
    6
    Quote Originally Posted by anduril462 View Post
    Code:
    int temp[31][2] = {0}, tempavg[31][2] = {0};
    How many columns do temp and tempavg have?

    Note, you really, really should have constants for these numbers. It would help you avoid such mistakes
    Code:
    #define NUM_ROWS 31
    #define NUM_COLS 3
    int temp[NUM_ROWS][NUM_COLS]...
    
    for (r = 0; r < NUM_ROWS; r++) {
        for (c = 0; c < NUM_COLS; c++) {  // use NUM_COLS-1 if you want to skip the last column
    Reads much better, and much easier if you ever want to change number of rows/columns.
    Thank you for the pointer. I previously had it that way and then changed it to the actual numerical values to try to make it easier to understand in my head when I was troubleshooting the problem.

    I'll change it back to use constants. Thanks again for the quick replies. Now I just have to figure out how to make that 3rd column the average of the first two columns but I think I've got the logic for that.

  6. #6
    Registered User
    Join Date
    Apr 2014
    Posts
    6
    Thanks again guys. Can't believe I let something so small hold me up for so long. Here's my finished code that prints an array with minimum temperature, maximum temperature and average temperature per day for January.

    It then prints the minimum temperature for the month, max temperature for the month and times the temperature was within 10 degrees of the minimum and maximum.

    It appears to work properly. Any constructive criticism is welcome:

    Code:
    #include <stdio.h>
    #include <math.h>
    #define ROWS 31
    #define COLUMNS 3
    FILE *inptr;
    
    
    int main()
    {
    	int temp[ROWS][COLUMNS] = {0};
    	int i, j, tempmax, tempmin, tempmincount, tempmaxcount;
    	inptr = fopen("ProgrammingProject14.txt", "r");
    	
    	//Following code reads in values to temp[][] from file ProgrammingProject14.txt:
    	for (i = 0; i < ROWS; i++)
    	{
    		for (j = 0; j < 2; j++)
    		{
    			fscanf(inptr, "%d", &temp[i][j]);
    		}
    	}
    	fclose(inptr);
    	
    	//Following code calculates the average of columns 1 and 2 and puts value in column 3:
    	for (i = 0; i < ROWS; i++)
    	{
    		temp[i][2] = (temp[i][0] + temp[i][1]) / 2;
    	}
    	
    	//Following code calculates the minimum temp for the month:
    	tempmin = temp[0][0];
    	for (i = 0; i < ROWS; i++)
    	{
    		if (temp[i][0] < tempmin)
    		{
    			tempmin = (temp[i][0]);
    		}
    	}
    	
    	//Following code calculates the maximum temp for the month:
    	tempmax = temp[0][1];
    	for (i = 0; i < ROWS; i++)
    	{
    		if (temp[i][1] > tempmax)
    		{
    			tempmax = (temp[i][1]);
    		}
    	}
    	
    	//Following code counts the number of times the number of times the minimum temp for the month is within 10 degrees of the lowest:
    	tempmincount = 0;
    	for ( i = 0; i < ROWS; i++)
    	{
    		if (temp[i][0] <= tempmin + 10)
    		{
    			tempmincount++;
    		}
    	}
    	
    	//Following code counts the number of times the number of times the minimum temp for the month is within 10 degrees of the lowest:
    	tempmaxcount = 0;
    	for ( i = 0; i < ROWS; i++)
    	{
    		if (temp[i][1] >= tempmax - 10)
    		{
    			tempmaxcount++;
    		}
    	}
    	
    	//Following code prints 2d array temp[]:
    	printf("    Temperatures\n");
    	printf("Low\tHigh\tAverage\n");
    	for (i = 0; i < ROWS; i++)
    	{
    		for(j = 0; j < COLUMNS; j++)
    		{
    			printf("%d\t", temp[i][j]);
    		}
    	printf("\n");
    	}
    	printf("\nMinimum Temperature for the month: %d\n", tempmin);
    	printf("Maximum Temperature for the month: %d\n", tempmax);
    	printf("Number of days temperature was within 10 degrees of minimum: %d\n", tempmincount);
    	printf("Number of days temperature was within 10 degrees of maximum: %d\n", tempmaxcount);
    	
    	
    	return 0;
    }

  7. #7
    Registered User
    Join Date
    Mar 2012
    Location
    the c - side
    Posts
    373
    Overall it looks good.

    But global variables should be avoided in general, and here there is absolutely no reason to use them. So inptr should be declared in main() along with the rest of the variables.

  8. #8
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Constructive criticism


    Compile with warning level at maximum:
    Code:
    $ make foogcc -Wall -ggdb3 -pedantic -std=gnu99 -O0 -o foo foo.c -lm -lpthread -lrt
    foo.c: In function ‘main’:
    foo.c:10:5: warning: missing braces around initializer [-Wmissing-braces]
    foo.c:10:5: warning: (near initialization for ‘temp[0]’) [-Wmissing-braces]
    For every nested aggregate type (array/multi-dimensional array, union, struct), you should have a set of curly braces for the initializer, delineating the sub-objects:
    Code:
    int temp[ROWS][COLUMNS] = {{0}};


    Check all your file function (fopen, fscanf) for errors. If encountered, print a useful message (look into perror or strerror functions). If need be, exit (if you can't read the data, no point in continuing).


    Don't use global variables (inptr). Read this link. Instead, declare the variable in the appropriate function and pass it to other functions as needed -- this is trivial for you, you only have a main function.


    Avoid all magic numbers/unnamed constants. Also, pick names that describe what the data really represents. I used ROWS and COLS because I didn't look at what the data represented (shame on me, being so lazy/careless). A better name for ROWS would be NUM_DAYS. A better name for COLS might be NUM_TEMPS. You could create an enum that describes what each column is:
    Code:
    enum {
        TEMP_MIN,
        TEMP_MAX,
        TEMP_AVG,
        NUM_TEMPS
    };
    Also, define something like MIN_TEMP_COUNT_DIFF and MAX_TEMP_COUNT_DIFF as 10, so you can change that "window" size of acceptable min temps easily.
    TEMP_MIN will be 0, TEMP_MAX 1 and TEMP_AVG 2 -- which are the corresponding array indices. NUM_TEMPS will be 3, which is what you will use for your declaration (3 columns in the array) and for loops to process those columns.


    Break your code into functions that are reusable. Consider something like
    Code:
    int get_min_temp(int monthly_temps[][NUM_TEMPS], int num_days)
    {
        int i, min_temp;
       ...
        for (i = 0; i < num_days; i++)
            // find min temp
    
        return min_temp;
    }
    ...
    // in main
    int min_temp = get_min_temp(temps, sizeof(temps) / sizeof(temps[0]));
    Making functions like that make your code more maintainable and reusable. Imagine if you had two months worth of temps, and you wanted to compare their min, max and avg temps. You would either have to write the code twice and find/fix bugs twice, or write/debug it once, and simply call it (one line of code) twice.

    The sizeof trick that I used ensures you always pass the right number of elements for the array. If I change temps to be NUM_DAYS, or NUM_HOURS (for hourly stats), I don't need to change that line.

  9. #9
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    The 2-d array works, but is not ideal, since the columns aren't really used as sequential data, i.e. there is no real relation between MIN being column 0, MAX column 1, etc. Their order is irrelevant.

    Even better would be to use an array of structs. That way you only have a 1-d array, but each element has several "sub-elements" that you can give useful names:
    Code:
    struct temp_data {
        int min_temp;
        int max_temp;
        int avg_temp;
    };
    ...
    // in main
    struct temp_data monthly_temps[NUM_DAYS];
    ...
    monthly_temp[i].avg_temp = ...;
    That would be a much easier/more natural way to do this than having an enum to describe what each column represents.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Reading values from a csv file in c into an array
    By Dogbert in forum C Programming
    Replies: 9
    Last Post: 01-26-2014, 11:56 AM
  2. Replies: 11
    Last Post: 01-12-2013, 02:04 AM
  3. Replies: 7
    Last Post: 04-25-2012, 04:30 AM
  4. Replies: 12
    Last Post: 09-23-2010, 11:49 AM
  5. assigning values in file to an array
    By divinyl in forum C++ Programming
    Replies: 9
    Last Post: 07-29-2003, 08:33 AM