How to use input arguments?

Discussion in 'C Programming' started by MM, Jul 10, 2003.

  1. MM

    MM Guest

    Hi there,

    How can I change my code (below) so that I use an "input argument" to
    specify the file name of the input file? For example, if I compile the code
    and that the application then gets the name "splitdata", then I want to be
    able to call my application with something like this (datafile.txt will then
    be the name of the input file):

    splitdata datafile.txt

    In the code as I have it now, the name of the input file is specified in
    line 13:

    char tname[] = "Example.txt";

    So, I want to skip this "hard coded" name specification. (The length of the
    input file name is not known.)

    Thanks in advance,

    MM

    =====================================================
    === Code, including line numbers (without line numbers is below this one)
    ===
    =====================================================

    1: #include <stdio.h>
    2: #include <stdlib.h>
    3: #include <string.h>
    4:
    5: #define DATASTART "\\Data:"
    6: #define BLOCKSTART "Time"
    7:
    8: int main()
    9: {
    10: FILE *fh, *fp, *fq;
    11: char hname[] = "header.dat"; // name of header output file
    12: char fname[6+2+4+1]; // name of data block output files,
    dblockNN.dat
    13: char tname[] = "Example.txt"; // name of input file to split
    14: char buf[1001]; // max line length is 1000 characters
    15: char numdb[] = "NumDataBlocks=";
    16: int i = 0;
    17:
    18: // open input file for reading
    19: if((fq=fopen(tname, "r")) == 0) {
    20: perror(tname);
    21: exit(EXIT_FAILURE);
    22: }
    23:
    24: // open header output file
    25: if((fh=fopen(hname, "w")) == 0) {
    26: perror(fname);
    27: exit(EXIT_FAILURE);
    28: }
    29:
    30: // print data to header file
    31: // if start of data segment is found then close header file
    32: while(fgets(buf, sizeof buf, fq) != 0) {
    33: if(strncmp(DATASTART, buf, 6) == 0) {
    34: fclose(fh);
    35: break;
    36: }
    37: fputs(buf, fh);
    38: }
    39:
    40: // write data block output files
    41: while(fgets(buf, sizeof buf, fq) != 0) {
    42: // lines starting with '#' and blank lines are skipped
    43: if(buf[0] == '#' || buf[0] == '\n')
    44: continue;
    45:
    46: // write each block to a separate file
    47: if(strncmp(BLOCKSTART, buf, 4) == 0) {
    48: if(i > 0)
    49: fclose(fp);
    50: sprintf(fname, "dblock%02d.dat", ++i);
    51: if((fp=fopen(fname, "w")) == 0) {
    52: perror(fname);
    53: exit(EXIT_FAILURE);
    54: }
    55: }
    56: fputs(buf, fp);
    57: }
    58:
    59: // close files
    60: fclose(fp);
    61: fclose(fq);
    62:
    63: // open header output file again and print the number of data blocks
    found last in the file
    64: if((fh=fopen(hname, "a")) == 0) {
    65: perror(fname);
    66: exit(EXIT_FAILURE);
    67: }
    68: sprintf(numdb, "%s%d%s", numdb, i, "\n");
    69: fputs(numdb, fh);
    70: fclose(fh);
    71:
    72: return 0;
    73: }

    =========================
    === Code without line numbers ===
    =========================

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

    #define DATASTART "\\Data:"
    #define BLOCKSTART "Time"

    int main()
    {
    FILE *fh, *fp, *fq;
    char hname[] = "header.dat"; // name of header output file
    char fname[6+2+4+1]; // name of data block output files,
    dblockNN.dat
    char tname[] = "Example.txt"; // name of input file to split
    char buf[1001]; // max line length is 1000 characters
    char numdb[] = "NumDataBlocks=";
    int i = 0;

    // open input file for reading
    if((fq=fopen(tname, "r")) == 0) {
    perror(tname);
    exit(EXIT_FAILURE);
    }

    // open header output file
    if((fh=fopen(hname, "w")) == 0) {
    perror(fname);
    exit(EXIT_FAILURE);
    }

    // print data to header file
    // if start of data segment is found then close header file
    while(fgets(buf, sizeof buf, fq) != 0) {
    if(strncmp(DATASTART, buf, 6) == 0) {
    fclose(fh);
    break;
    }
    fputs(buf, fh);
    }

    // write data block output files
    while(fgets(buf, sizeof buf, fq) != 0) {
    // lines starting with '#' and blank lines are skipped
    if(buf[0] == '#' || buf[0] == '\n')
    continue;

    // write each block to a separate file
    if(strncmp(BLOCKSTART, buf, 4) == 0) {
    if(i > 0)
    fclose(fp);
    sprintf(fname, "dblock%02d.dat", ++i);
    if((fp=fopen(fname, "w")) == 0) {
    perror(fname);
    exit(EXIT_FAILURE);
    }
    }
    fputs(buf, fp);
    }

    // close files
    fclose(fp);
    fclose(fq);

    // open header output file again and print the number of data blocks
    found last in the file
    if((fh=fopen(hname, "a")) == 0) {
    perror(fname);
    exit(EXIT_FAILURE);
    }
    sprintf(numdb, "%s%d%s", numdb, i, "\n");
    fputs(numdb, fh);
    fclose(fh);

    return 0;
    }
    MM, Jul 10, 2003
    #1
    1. Advertising

  2. MM

    Derk Gwen Guest

    # splitdata datafile.txt
    #
    # In the code as I have it now, the name of the input file is specified in
    # line 13:
    #
    # char tname[] = "Example.txt";
    #
    # So, I want to skip this "hard coded" name specification. (The length of the
    # input file name is not known.)

    # 8: int main()

    int main(int argc,char **argv) {...}

    On systems that provide a command line interface, if you call the program with
    'splitdata datafile.txt', usually it will set
    argc = 2
    argv[0] = "splitdata"
    argv[1] = "datafile.txt"
    argv[2] = 0

    So you can do something like
    char *tname = argc>=2 ? argv[1] : "Example.txt";

    --
    Derk Gwen http://derkgwen.250free.com/html/index.html
    GERBILS
    GERBILS
    GERBILS
    Derk Gwen, Jul 10, 2003
    #2
    1. Advertising

  3. MM

    MM Guest

    "Derk Gwen" <> wrote in message
    news:...
    >
    > int main(int argc,char **argv) {...}
    >
    > On systems that provide a command line interface, if you call the program

    with
    > 'splitdata datafile.txt', usually it will set
    > argc = 2
    > argv[0] = "splitdata"
    > argv[1] = "datafile.txt"
    > argv[2] = 0
    >
    > So you can do something like
    > char *tname = argc>=2 ? argv[1] : "Example.txt";
    >


    Yes, that works just fine! Many thanks for the help.

    MM
    MM, Jul 10, 2003
    #3
  4. MM

    Richard Bos Guest

    "MM" <> wrote:

    > How can I change my code (below) so that I use an "input argument" to
    > specify the file name of the input file? For example, if I compile the code
    > and that the application then gets the name "splitdata", then I want to be
    > able to call my application with something like this (datafile.txt will then
    > be the name of the input file):
    >
    > splitdata datafile.txt


    That's called "command line arguments" in C, not "input arguments". To
    use them, you define main() as

    int main(int argc, char argv**)

    and read your C book for a complete explanation of these arguments. In a
    nutshell, though:

    - argc contains the number of arguments plus one.
    - If argc>0, then argv[0] contains the name of the program (though not
    necessarily in a format that's useful to you, especially if you need
    directory information).
    - If argc>1, then argv[1] through argv[argc-1] are the command line
    parameters.
    - argv[argc] is a null pointer.

    Richard
    Richard Bos, Jul 10, 2003
    #4
  5. MM

    MM Guest

    "David Rubin" <> wrote in message
    news:mdcPa.23369$...
    > MM wrote:
    >
    > [snip]
    > > int main()
    > > {

    > [snip]
    > > char numdb[] = "NumDataBlocks=";

    > [snip]
    > > sprintf(numdb, "%s%d%s", numdb, i, "\n");

    >
    > This yields undefined behavior since you're trying to write more bytes

    than
    > you've allocated for numdb.
    >
    > /david
    >


    Ok, then is this a better way to do it?

    [snip]
    char numdb[4+2+1+1];
    [snip]
    sprintf(numdb, "%s%02d%s", "NDB=", i, "\n");

    Also, maybe you have a nice way to (platform independently!) remove/delete a
    file in C?
    Using for example
    system("del filename.txt");
    doesn't work, of course, since "del" is not OK in UNIX...

    Thanks again, David!

    MM
    MM, Jul 10, 2003
    #5
  6. "MM" <> wrote in
    news:e5ePa.1075$:

    > Ok, then is this a better way to do it?
    >
    > [snip]
    > char numdb[4+2+1+1];
    > [snip]
    > sprintf(numdb, "%s%02d%s", "NDB=", i, "\n");
    >


    Probably.

    > Also, maybe you have a nice way to (platform independently!)
    > remove/delete a file in C?
    > Using for example
    > system("del filename.txt");
    > doesn't work, of course, since "del" is not OK in UNIX...
    >


    remove()
    Finny Merrill, Jul 10, 2003
    #6
  7. On Thu, 10 Jul 2003 15:44:43 +0200, in comp.lang.c , "MM"
    <> wrote:

    >
    >"David Rubin" <> wrote in message
    >news:mdcPa.23369$...
    >> MM wrote:
    >>
    >> [snip]
    >> > int main()
    >> > {

    >> [snip]
    >> > char numdb[] = "NumDataBlocks=";

    >> [snip]
    >> > sprintf(numdb, "%s%d%s", numdb, i, "\n");

    >>
    >> This yields undefined behavior since you're trying to write more bytes than
    >> you've allocated for numdb.

    >
    >Ok, then is this a better way to do it?


    make numdb big enough (malloc sounds like a useful method), and don't
    copy it into itself which ISTR is also undefined behaviour.

    bigenough = strlen("NumDataBlocks=") + aslongas_i_could_be +2);
    char* numdb = malloc(bigenough);
    sprintf(numdb, "NumDataBlocks=%d\n", i);


    >Also, maybe you have a nice way to (platform independently!) remove/delete a
    >file in C?


    remove();

    RTFM !!

    --
    Mark McIntyre
    CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
    CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>


    ----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
    http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
    ---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
    Mark McIntyre, Jul 10, 2003
    #7
  8. On Thu, 10 Jul 2003 15:44:43 +0200, "MM" <> wrote:

    >
    > "David Rubin" <> wrote in message
    > news:mdcPa.23369$...
    > > MM wrote:
    > > [snip]
    > > > char numdb[] = "NumDataBlocks=";

    > > [snip]
    > > > sprintf(numdb, "%s%d%s", numdb, i, "\n");

    > >
    > > This yields undefined behavior since you're trying to write more bytes

    > than
    > > you've allocated for numdb.
    > >

    Plus the (total) overlap, as noted elsethread.

    > Ok, then is this a better way to do it?
    >
    > [snip]
    > char numdb[4+2+1+1];
    > [snip]
    > sprintf(numdb, "%s%02d%s", "NDB=", i, "\n");
    >

    As long as the value of i fits in two digits this is valid; if it is
    larger, *printf will expand the field, and for sprintf overflow.
    Using snprintf as of C99, or in many C89s as an extension possibly
    under a variant name like _snprintf, you can prevent overflow and UB,
    but (instead) get incomplete output you must check for and deal with.

    If the string NDB is constant, it is simpler and IMO preferable to
    include it in the format string:
    snprintf (numdb, sizeof numdb, "NDB=%02d\n", i);

    and if the string varies I would consider something like:
    char numdb[sizeof("NDB=") -1 +2+1+1] = "NDB=";
    ...
    snprintf (numdb+4, 2+1+1, "%02d\n", i);

    In either case, the %02d forces a _minimum_ two digits; if you don't
    need this, and your format would be unambiguous and legible without,
    %d is sufficient and simpler.

    But, in your original code, the only thing you do with this output is
    write it to a file. You could accomplish that with fprintf and not
    need to worry about ensuring or checking that your line buffer is (at
    least) the right size; output files are as large as necessary, at
    least up to platform limits you probably cannot exceed anyway.

    - David.Thompson1 at worldnet.att.net
    Dave Thompson, Jul 15, 2003
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Edward Diener
    Replies:
    14
    Views:
    4,941
    Josiah Carlson
    Apr 6, 2004
  2. Neo
    Replies:
    10
    Views:
    658
    sushant
    Jan 20, 2005
  3. tutmann
    Replies:
    4
    Views:
    436
  4. jmborr
    Replies:
    1
    Views:
    412
    Stargaming
    Nov 3, 2007
  5. Replies:
    3
    Views:
    821
Loading...

Share This Page