-1

I have a "Temp.dat" with 200 lines that looks like this:

0.060493 1 0.5 1
1.596961 0 0.1 2
0.87758  1 0.3 1.5
0.165453 1 0   3
0.07085  1 0.3 4
0.125379 1 0.2 3
0.454202 1 0.2 2
0.373227 1 0.3 1
0.131486 1 0.3 3
0.867477 0 0.5 4
0.122609 0 0.8 9

I am trying to read each line and store each column of data into separate arrays with the following code:

#include <stdio.h>
#include <stdlib.h>
#define MAX 200

int main(){

  double x[MAX], y[MAX];
  double a, b;
  int m = 0;
  FILE* file; 
  file = fopen("Temp.dat", "r");
  if ( file != NULL ){
      /* Read the two columns. */
      while(fscanf(file, "%d %d", &a, &b) == 2)
      { x[m] = a;
        y[m] = b;
        m++;
      }
  }
  printf("%d %d\n", x[4], y[1]); # Test the stored inputs of the two arrays
  return(0);
}    

When I tried printing out the result, it gave 1 13258992, rather than 0.165453 0. I cannot understand where it got the pair 1 13258992, as I thought the line fscanf(file, "%d %d", &a, &b) == 2 did what it's supposed to do: go through each row of the file Temp.dat and read the two double-type integers, then stored in the two arrays x[MAX] and `y[MAX]. Therefore, could anyone please help me fix this issue?

Another question: After storing the two columns above in two arrays x[MAX] and y[MAX], I would like to sort the two arrays in an increasing order based on the values in the first array x[MAX]. This would look like:

    0.060493 1
    0.07085  1
    0.122609 0
    0.125379 1
    0.131486 1
    0.165453 1
    0.373227 1
    0.454202 1
    0.867477 0

How could I do this sorting routine in C, as it's quite hard to arrange the elements in y[MAX] to follow the order of their corresponding elements in x[MAX]?

2
  • @Pablo: Thank you for your help. I added the condition in the while, and change %d to %lf, but the result is still incorrect. Now it gave me -1 34902256 for the same x[4] y[1]. Could you give me some hints on how to sort the second array while I am swapping each element of the first array? Commented Feb 19, 2018 at 2:56
  • I removed my comment and posted it as an answer. You had the same error in the printf call. See my answer. Commented Feb 19, 2018 at 3:00

3 Answers 3

1

For starters try:

double a;
int b;

...

fscanf(file, "%f %d", &a, &b)

You initialized a and b as double type but you are reading integers (%d) from the copy.dat file. b is an int value so leave %d in the fscanf and change the initialization.

Sign up to request clarification or add additional context in comments.

3 Comments

I got it now. Thanks a ton. Could you help with the sort function?
Do a search for a bubble sort. It’s not the most efficient or prettiest sort but it is easy to code and it will work through 200 values basically instantly.
To get the y array to follow the sort of the x array apply the search logic to the x array only but swap both the x and y array at the same time.
1

First add && m < MAX in the while conditions, so that you don't overflow the buffer.

scanf expects with %d a pointer to int, not to double and it will parse the content as an integer. You have to use %lf to parse doubles. The same applies to the printf call:

while(fscanf(file, "%lf %lf", &a, &b) == 2 && m < MAX)
    ...

...

printf("%lf %lf\n", x[4], y[1]);

I get

0.070850 0.000000

which is the fifth line of you dat file (not the fourth, array indices start by 0, not 1).

As for your other question:

I'm afraid you have to write your own sort function.

2 Comments

I got the first part now!! Thanks a ton for your help, Pablo. I am using Mac's OS. Could you please help show me how to do this with qsort_r?
Like I said, qsort_r is a GNU extension of the GCC compiler, you would need to compile it with the GCC compiler. Sorry to confuse you, but even qsort_r would not help here, because you need to know which indices in the array are being compared and qsort passes the values, not the indices. I'm afraid you would have to write your own sorting function.
0

You can declare a structure with x and y, so that the two values are tied together, x and y will keep their relation when array elements are swapped during sort. Example:

struct data_t
{
    double x;
    int y;
};

int compare(const void *a, const void *b)
{
    const struct data_t *m = a;
    const struct data_t *n = b;
    if(m->x == n->x)
        return m->y > n->y;
    return m->x > n->x;
}

int main(void) 
{
    struct data_t data[MAX];
    FILE* file = fopen("Temp.dat", "r");
    int count = 0;
    while(fscanf(file, "%lf %d", &data[count].x, &data[count].y) == 2)
    {
        count++;
        if (count == MAX)
            break;
    }

    qsort(data, count, sizeof(struct data_t), compare);
    for(int i = 0; i < count; i++)
        printf("%lf %d\n", data[i].x, data[i].y);
    return 0;
}

Use %lf for double values, or use %f for float , as shown in the other answers

About the compare function, lets say you have these values in your data:

0.060493 1
0.060493 5
0.060493 2

In this case the x value from first element is same as x value from the other element. If you only test for m->x > n->x then sorting does not occur. So you want to compare m->y > n->y if x is the same.

qsort is a standard C function. It doesn't know your data type, we have to have to tell it about the data type. That's done inside the compare function which receives pointers a and b, we know these are pointers to elements in data array, so that's reason behind the conversion.

The data set can contain up to 200 items since we declared it as struct data_t data[MAX]; where MAX is 200.


Edit 3 ******
Working with arrays, declare the array:

double arr[MAX + 1][8]

Note that the first index of the array is rows from 0 to MAX. It's set up this way so it can be sorted later. Now we can read the file directly in to the array, and sort the array (no need for structure). Make sure you don't mix this up with the old solutions which had arr[8][MAX + 1]

int compare_2d_array(const void *pa, const void *pb)
{
    double a = *(double*)pa;
    double b = *(double*)pb;
    return a > b;
}

int main(void)
{
    //array with MAX + 1 rows, and 8 columns, initialized to zero
    double arr[MAX + 1][8] = { 0 };
    FILE* file = fopen("temp.dat", "r");
    int count = 0;
    while(fscanf(file, "%lf %lf", &arr[count][0], &arr[count][1]) == 2)
    {
        count++;
        if(count == MAX) break;
    }

    qsort(arr, count, sizeof(arr[0]), compare_2d_array);

    //arr[0] and arr[1] are ready, now set up the other columns:
    for(int i = 0; i < count; i++)
    {
        //make modifications to other columns
        arr[i][2] = i ? arr[i - 1][0] : 0;
        arr[i][3] = arr[i][0];
        arr[i + 1][4] = i + 1;

        printf("%.6lf %.0lf %.6lf %.6lf %.0lf\n", 
                    arr[i][0], arr[i][1], arr[i][2], arr[i][3], arr[i][4]);
    }
    return 0;
}

13 Comments

I tried out your code and it works fantastically with the dataset!! Many thanks for your help. I have some questions though: could you help explain to me why the return m->y > n->y? in your compare() function? Also, the declaration of a pointer const struct data_t *m = a helps on?? Is struct data_t = a dataset with $200$ pairs of (x,y)?
Many thanks for your help, as it's quite clear!! I have another question: from the two columns, assume the first denotes the time $T$, and the second means 1= Death occurs and 0 = Censor occurs. I want to create two arrays, which store the following computed quantity: first array stores number of people that are alive and not censored between any two successive time periods, and second array stores number of death occurs during the same time periods. May you help assist on how i am supposed to do this with int array[MAX] and for loop?
Look at (Edit 3 ****), include that in your new question along with input sample and the expected output
I got confused. My previous comment doesn't make sense. You still have one 2-d array. There is no 4-d array. Keep the function proc as compare_2d_array(const void *element1, const void *element2)
You can ask a new question based on "sorting 2-d array, based on 2 or more columns". Also, in another question I showed how to sort a structure, that was a similar concept.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.