Thread: Trying to use argv to access multiple files

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    38

    Trying to use argv to access multiple files

    Ideally, I would like to be able to tell my program "autocorrelation *.txt" in a directory and have it process each file in the directory, returning each file's results to a new file ending in "-AUTO.txt"

    For example, if I had APPLE.txt, BANANA.txt, and ORANGE.txt, this program should be returning the files APPLE-AUTO.txt, BANANA-AUTO.txt, and ORANGE-AUTO.txt after running "autocorrelation.exe"

    Instead, I'm seg faulting. What am I doing wrong?

    Code:
    /*********************************************************************
    * This program is designed to calculate a series of autocorrelations *
    * based on a set of data that is called when the program is run.     *
    * The set of data needs to be in "float" format (i.e., nothing but   *
    * numbers), or else the program will generate an error.  The         *
    * resulting file will also be a series of numbers, meant to go into  *
    * some kind of graphing program to plot the original data against    *
    * the values of the autocorrelations for each point.                 *
    *********************************************************************/
    
    /* Autocorrelation Program, Written By Don Ford */
    
    #include <stdio.h>
    #include <conio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[]){
        FILE* dataFile;
        FILE* outputFile;
        char string[80];
        char *old_filename;
        char new_filename[256];
        char * ext;
        double x[1000];
        int i = 0;
        int j;
        int number_of_values;
        double x_sum = 0.0;
        double x_average;    
        double values = number_of_values;
        int k;
        int t;
        double y[number_of_values];
        double sum_of_squares = 0.0;
        double numerator = 0.0;    
        char buffer[80];
        
        for (j=1; j<argc; j++){
            old_filename = argv[j];
            dataFile = fopen(argv[j], "r");
                     if (dataFile == NULL){
                        fputs("File error", stderr);
                        exit(1);
                        }
            while (fgets(string, 80, dataFile) != NULL){
                  if (!isalpha(string[0])){
                     x[i] = strtof(string, NULL);
                     i++;
                     }
                  }          
            fclose(dataFile);
            number_of_values = i;
    
            for (i=0; i<number_of_values; i++){
                x_sum += x[i];
                }
            x_average = (x_sum/values);
    
            /* Now, we actually calculate the autocorrelation! */
            for (t=0; t<number_of_values; t++){
                sum_of_squares += ((x[t] - x_average)*(x[t] - x_average));
                }
            
            for (k=0; k<(number_of_values/2); k++){
                for (t=0; t<(number_of_values - k); t++){
                    numerator += ((x[(t+k)] - x_average)*(x[t] - x_average));
                    }
                y[k] = (numerator/sum_of_squares);
                numerator = 0.0;
                }
            
            ext = strrchr(old_filename, '.');
            strncpy(new_filename, old_filename, argv[j]-ext+1);
            strcat(new_filename, "-AUTO.txt");
            printf("\"%s\" created.\n", new_filename);
            
            outputFile = fopen(new_filename, "wb");
            if (outputFile == NULL){
               fputs("File error", stderr);
               exit(2);
               }
            
            snprintf(buffer, 80, "Lag%4Autocorrelation\0");
            fputs(buffer, outputFile);
            fputs("\n", outputFile);
            snprintf(buffer, 80, "---%4---------------\0");
            fputs(buffer, outputFile);
            fputs("\n", outputFile);
            for (i=0; i<(number_of_values/2); i++){
                snprintf(buffer, 80, "%2d%10.8f\0", i, y[i]);
                fputs(buffer, outputFile);
                fputs("\n", outputFile);
                }
            fclose(outputFile);
            }
    
        return 0;
    }

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You should just scatter around a bunch of printf statements and figure out for yourself where it's crashing. Without us having your data, and without something motivating me to play guessing games with your code, to be honest, it's not worth the effort.

    You don't give any indicator as to where you are when it crashes. Is it when you're running through your data? When you open a file? Close a file? Are any new files getting created? Honestly, you'd be better off just making a simple program to first be sure you know how to read through multiple command line arguments.

    If you know you're doing that right, try just renaming all of those files. If you know you can do that right, now start worrying about their contents.


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Have you been able to pinpoint the code segment that's segfaulting by running it through gdb.

  4. #4
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    A debugger might not be helpful in pinpointing what I see as problem number one.
    Code:
    int number_of_values;
    double values = number_of_values;
    double y[number_of_values];
    number_of_values has no value (or rather, its value is indeterminate). Yet it's being used to initialize another variable and, more insidiously, as the size of an array.

    To the OP: The last line above (the array declaration) uses the value of number_of_values at the creation of the array; the array does not track changes in number_of_values. So if number_of_values happens to contain the value 1, then the array is one double long forever (or at least until it goes out of scope). The same goes for your "values" variable; it takes the value of whatever number_of_values is at the time it is created, and will not change willy-nilly as number_of_values changes.

    I would also caution you to be careful with strncpy(). It does not automatically create a string, which means that using strcat() after strncpy() is dicey unless you make sure to null-terminate the new string yourself.

    Also, if possible, turn up compiler warnings. You're missing the string.h and ctype.h headers; and you're embedding % signs in your snprintf() calls which snprintf() is interpreting as conversions. Use %% to get a literal % with snprintf(). And you need not add the '\0' to the end of string literals yourself, as they already contain one.

  5. #5
    Registered User
    Join Date
    Nov 2008
    Posts
    38
    cas was right. I've moved:
    Code:
    double values = number_of_values;
    double y[number_of_values];
    right after the while loop, so it now reads:
    Code:
            while (fgets(string, 80, dataFile) != NULL){
                  if (!isalpha(string[0])){
                     x[i] = strtof(string, NULL);
                     i++;
                     }
                  }          
            fclose(dataFile);
            number_of_values = i;
            double values = number_of_values;
            double y[number_of_values];
    which works. However, now, the program terminates (without error) after the autocorrelation is calculated, right before the code block that starts:
    Code:
            ext = strrchr(old_filename, '.');
            strncpy(new_filename, old_filename, argv[j]-ext+1);
            strcat(new_filename, "-AUTO.txt");
    ...

    So, what's this part doing wrong?
    Last edited by DonFord81; 04-02-2009 at 02:44 PM.

  6. #6
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    int number_of_values;
        double x_sum = 0.0;
        double x_average;    
        double values = number_of_values;
        int k;
        int t;
        double y[number_of_values]
    How big is your array when it is created? (Assuming you're actually compiling this as C99, so that it actually compiles...)


    Quzah.
    Hope is the first step on the road to disappointment.

  7. #7
    Registered User
    Join Date
    Nov 2008
    Posts
    38
    Quote Originally Posted by DonFord81 View Post
    cas was right. I've moved:
    Code:
    double values = number_of_values;
    double y[number_of_values];
    right after the while loop, so it now reads:
    Code:
            while (fgets(string, 80, dataFile) != NULL){
                  if (!isalpha(string[0])){
                     x[i] = strtof(string, NULL);
                     i++;
                     }
                  }          
            fclose(dataFile);
            number_of_values = i;
            double values = number_of_values;
            double y[number_of_values];
    which works. However, now, the program terminates (without error) after the autocorrelation is calculated, right before the code block that starts:
    Code:
            ext = strrchr(old_filename, '.');
            strncpy(new_filename, old_filename, argv[j]-ext+1);
            strcat(new_filename, "-AUTO.txt");
    ...
    Incidentally, this is the first argc/argv program I've written. It worked when I handled each file separately, so I think I got overconfident. *snicker*

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Ah, I missed Cas' post.


    Quzah.
    Hope is the first step on the road to disappointment.

  9. #9
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Code:
    strncpy(new_filename, old_filename, argv[j]-ext+1);
    What value does the expression "argv[j]-ext+1" have?

    And to expand a bit on my warning earlier about strncpy(): From what I'm guessing you're trying to copy, from old_filename, everything up to the extension. Thus there will never be a null character in the source and so a string will never be created (we'll assume that your strrchr() call always returns a non-null pointer).

    If this is indeed the case, then I'd highly recommend memcpy() instead of strncpy(). strncpy() really was designed to be use in a specific case in unix, where an array of char was usually null terminated (thus a string) except in the case where the length of the string (not counting the null character) was exactly the length of the array; then the entire array was filled and no null character stored.

    Its name, unfortunately, tags it as a string handling function which it is only sporadically. By using memcpy() you're not tricking yourself into thinking you're dealing with a string. If you do decide to use strncpy(), there are a couple of things to keep in mind:

    The third argument (the size argument) must, absolutely must be no larger than the size of the array you're passing in as the first argument. Otherwise you might overrun the array, which is no good business. Generally the third argument to strncpy() is used to give the size of the first array, much the way snprintf() is used (though snprintf() is smarter than strncpy()).

    Once you've called strncpy(), and you want a string (which is almost always, in those rare cases that you should use strncpy()), then you must null-terminate it yourself. The general call to strncpy() should look something like:
    Code:
    strncpy(target, source, n);
    target[n] = 0;
    In this case, if target is 100 bytes, then n should be 99. By doing this, you're guaranteeing a string has been created.

    Of course, the way you're using strncpy() is not the normal method (from what I can tell), but as I mentioned, a method for which memcpy() is probably better; you're essentially using strncpy() as a poor man's memcpy(). You are limiting the source length, not the target length (which you hope is long enough to hold what you're copying).

    I'm not certain this whole rambling post is very useful to you, so the two things I urge you to keep in mind are: strncpy() is a function usually best left alone, but if you must use it, remember to null terminate your strings manually.

  10. #10
    Registered User
    Join Date
    Nov 2008
    Posts
    38
    My main question is: if I use "*.txt" as argv[1], will the program (when it functions correctly) go through all .txt files?

  11. #11
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Quote Originally Posted by DonFord81 View Post
    My main question is: if I use "*.txt" as argv[1], will the program (when it functions correctly) go through all .txt files?
    it is upto you what you program will do with the string "*.txt"
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  12. #12
    Registered User
    Join Date
    Nov 2008
    Posts
    38
    Quote Originally Posted by vart View Post
    it is upto you what you program will do with the string "*.txt"
    Does that mean I have to write a routine to have the program figure out what "*.txt" means?

  13. #13
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Quote Originally Posted by DonFord81 View Post
    Does that mean I have to write a routine to have the program figure out what "*.txt" means?
    yes, it does
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. header files and multiple files
    By Dedalus in forum C Programming
    Replies: 5
    Last Post: 06-16-2009, 09:21 AM
  2. Replies: 5
    Last Post: 02-25-2008, 06:35 AM
  3. Windows shell commands - multiple files
    By Magos in forum Tech Board
    Replies: 3
    Last Post: 02-28-2006, 01:56 AM
  4. Opening Multiple Files in sequence
    By wujiajun in forum C++ Programming
    Replies: 7
    Last Post: 01-16-2006, 08:47 PM
  5. Multiple Cpp Files
    By w4ck0z in forum C++ Programming
    Replies: 5
    Last Post: 11-14-2005, 02:41 PM

Tags for this Thread