Thread: unknown number of chars

  1. #1
    the Corvetter
    Join Date
    Sep 2001
    Posts
    1,584

    unknown number of chars

    I am writing this program that reads a string from a file. The thing is, it can be a whole sentence or whatever the user wants. How would I get an unknown number of chars? I don't want to use a character array, because then it would have to be something like string[1000] and that's just rediculous. But, if I use a char *, then I'm going to have to malloc the necessary amount of memory (therefore running into the same problem). I don't know how long the string will be!

    Thanks.

    --Garfield
    1978 Silver Anniversary Corvette

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    A linked list

    Code:
    struct line_segment {
        char buff[21];
        struct line_segment *next;
    };
    Each stores up to 20 chars, and you string as many of these as necessary together, using malloc to allocate each one.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Sep 2001
    Posts
    412
    Also, why is 1000 bytes ridiculous? You're most likely programming on a system where you could allocate 20 megs of memory without a problem -- why nitpick on 1K? I often use a 5K buffer for programs that use buffers.

    Honestly, as long as you're programming for 32-bit windows (console or GUI) you rarely need to worry about taking too much memory.

  4. #4
    Just one more wrong move. -KEN-'s Avatar
    Join Date
    Aug 2001
    Posts
    3,227
    or you could use that thing that dean wrote a while back...went something like:

    Code:
    #include <stdio.h>
    #include <malloc.h>
    #include <conio.h>
    
    int main(void)
    {
    
        char c, *input;
        int x=0;
        FILE *file;
        input = (char *)malloc(1);
    
        file = fopen("C:\File.txt", "r");
    
        while(c != '~')
        {
              c = fgetch(file);
              input[x] = c;
               x++;
               input = (char *)realloc(input, 1+x);
         }
    	
    	
         printf("\n%s\n",input);
         getch();
         free(input);
         fclose(file);
         return 0;
    }
    Last edited by -KEN-; 10-29-2001 at 05:18 PM.

  5. #5
    Just one more wrong move. -KEN-'s Avatar
    Join Date
    Aug 2001
    Posts
    3,227
    ...of course that assumes that you put a ~ at the end of your file...

  6. #6
    the Corvetter
    Join Date
    Sep 2001
    Posts
    1,584
    > A linked list

    struct line_segment {
    char buff[21];
    struct line_segment *next;
    };

    Each stores up to 20 chars, and you string as many of these as necessary together, using malloc to allocate each one. <

    I could do this, although how would I work through this? Would I implement it like this:
    Code:
    struct line_segment *line;
    
    struct line_segment {
        char buff[21];
        struct line_segment *next;
    };
    
    fgets(line->buff, sizeof(line), fp);
    But when I call fgets, that's where it gets confusing. Oh never mind, I'll just use getc, right? Then it'll be like this, right?:
    Code:
    for (x = 0; x < 21; ++x)
    fgetc(line->buff[x], fp) // I'm not sure that the arguments of fgetc are correct
                                       // I haven't used this function much
    So, would fgetc be the function to use?

    Thanks.

    --Garfield
    1978 Silver Anniversary Corvette

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Cmon Garfield, I thought you'd got the hang of this
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define SEG_LENGTH  21
    
    typedef struct line_segment {
        char buff[SEG_LENGTH];
        struct line_segment *next;
    } line_seg;
    
    line_seg *append_line ( line_seg *head, char *buff ) {
        // allocate (should check for NULL)
        line_seg *temp = malloc( sizeof(line_seg) );
    
        // copy data
        strcpy( temp->buff, buff );
        temp->next = NULL;
    
        // append to linked list
        if ( head == NULL ) {
            head = temp;
        } else {
            line_seg *tail = head;
            while ( tail->next != NULL ) {
                tail = tail->next;
            }
            tail->next = temp;
        }
        return head;
    }
    
    void print_line ( line_seg *head ) {
        while ( head != NULL ) {
            printf( "%s\n", head->buff );
            head = head->next;
        }
    }
    
    int main ( ) {
        line_seg *big_line = NULL;
        char buff[SEG_LENGTH];
    
        // read from stdin (or any FILE*)
        while ( fgets(buff,SEG_LENGTH,stdin) != NULL ) {
            big_line = append_line( big_line, buff );
            if ( strchr( buff, '\n' ) != NULL ) break;  // newline found
        }
        print_line( big_line );
        // free big_line - easy exercise for the reader :)
        return 0;
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    the Corvetter
    Join Date
    Sep 2001
    Posts
    1,584
    > Cmon Garfield, I thought you'd got the hang of this
    I do have the hand...with linked lists. I never had to work with strings like this before. Thanks.

    --Garfield
    1978 Silver Anniversary Corvette

  9. #9
    the Corvetter
    Join Date
    Sep 2001
    Posts
    1,584
    Code:
    while ( fgets(buff,SEG_LENGTH,stdin) != NULL ) {
            big_line = append_line( big_line, buff );
            if ( strchr( buff, '\n' ) != NULL ) break;  // newline found
        }
    Won't this not work, though? After all, fgets gets the string and then internally incrememts to read the next string on the next call, right? So, for every iteration, it's going to read a new line every time, right? Then it will only read 20 chars per line and then move on until the end of file. Am I understand this? Can you explain this code briefly, Salem? Thanks.

    --Garfield
    1978 Silver Anniversary Corvette

  10. #10
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Code:
    //______________________________________//
    int find_max( char *filename )
    {
    FILE *fpp;
    
    fpp = fopen(filename,"r") ;
    
    fseek(fpp,0L,SEEK_END);
    
    int filesize = ftell(fpp);
    
    rewind(fpp);
    
    char *buffer= (char *)malloc((sizeof (char )) * filesize);
    
    fread(buffer,filesize,1,fpp);
    
    fclose(fpp);
    
    int count_max=0;
    
    int max_sz=0;
    
    int len=strlen(buffer);
    
    char newline='\n';
    
    int d;
    
      for(d=0; d<len; d++)
        {
    if(isalpha(buffer[d]) || isdigit(buffer[d]) || isspace(buffer[d]) || isspunct(buffer[d]) && buffer[d] != newline)
                {
                 count_max++;              
                 }
    
            else {
                      if(count_max > max_sz)
                               {
                                max_sz = count_max;
                               }
    
                      count_max=0;
                   }
    
               }
    
    free(buffer);
    
    return max_sz;
    }




    //in main:


    int num = find_max("my_file.txt");

    char *buffer= (char *)malloc((sizeof (char )) * num);

    // or if you don't wanna malloc:

    char buffer[num];
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  11. #11
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Code:
    /**
    *** This code assumes the following:
    *** 1) You pass it a valid, open, file pointer.
    *** 2) You are at the point in the file where you want to read from.
    *** 2) You pass it a postivie integer for the amount to read.
    ***/
    char *fnread( FILE* fp, int n )
    {
       char *r = NULL,*s = NULL;
       int x=0;
       do
       {
          r = malloc( sizeof( char ) +1 );
          r[0] = fgetc( fp );
          r[1] = '\0';
          r = realloc( r, strlen( s ) + 2 );
          strncat( r, s, strlen( s ) + 2 );
          s = r;
          r = NULL;
       }
       while( !feof( fp ) && n > x++ );
       return s;
    }
    I believe that should do the trick. I didn't bother compiling this one, but it's logic looks sound to me.

    Quzah.

  12. #12
    the Corvetter
    Join Date
    Sep 2001
    Posts
    1,584
    Genuis, quzah. Sheer genius. I didn't even think of reallocating to accomidate the whole string.

    But, Salem (or anybody who can answer that), can you still explain my question about fgets and looping like that? It's really got me thinking. Thanks.

    --Garfield
    1978 Silver Anniversary Corvette

  13. #13
    Registered User pinko_liberal's Avatar
    Join Date
    Oct 2001
    Posts
    284
    As I was browsing through comp.lang.c I came across this code to read in arbitary number of characters.
    The cool thing about this code is that it mallocs just once , though it is a bit complicated .
    http://www.iedu.com/mrd/c/getsm.c

  14. #14
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Ug. That's nasty looking code. Can't you do the same thing this way:
    Code:
    char *fnread2( FILE*fp, int n )
    {
       char*c=NULL;
       int x=0;
       while( fgetc(fp) != EOF && x < n ) x++;
       c = malloc( sizeof(char) * x + 1 );
       fseek( fp, -x, SEEK_CUR );
       fread( c, 1, x, fp );
       c[x]='\0';
       return c;
    }
    That should work. You probably could just fseek ahead n spaces, and if you didn't get an error, fseek back the same number, malloc that block, and fread. The onlything I'm not sure of, is if you fseek say 40 bytes, and there are only 20, how do you know how many are available, since fseek doesn't return the number of bytes foreward it seeks. I suppose you could actually ftell, fseek, ftell and subtract that number...

    Quzah.

  15. #15
    Registered User pinko_liberal's Avatar
    Join Date
    Oct 2001
    Posts
    284
    your program may or may not work for a file opened in the text mode

    from K & R
    int fseek(FILE *stream,long offset,int origin)
    [bold]
    For a text stream , offset must must be 0 , or a value returned by ftell ( in which case the origin must be SEEK_SET) .
    [/bold]
    also you reading all the characters in the file ( fgetc ) and not using them at all.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 6
    Last Post: 02-19-2009, 07:19 PM
  2. Random number + guessing game trouble
    By Ravens'sWrath in forum C Programming
    Replies: 16
    Last Post: 05-08-2007, 03:33 AM
  3. Prime number program problem
    By Guti14 in forum C Programming
    Replies: 11
    Last Post: 08-06-2004, 04:25 AM
  4. help with a source code..
    By venom424 in forum C++ Programming
    Replies: 8
    Last Post: 05-21-2004, 12:42 PM
  5. Contest Results - May 27, 2002
    By ygfperson in forum A Brief History of Cprogramming.com
    Replies: 18
    Last Post: 06-18-2002, 01:27 PM