sorting the input

Discussion in 'C Programming' started by Nick Keighley, Apr 22, 2008.

  1. please include the subject in the body of your email:

    "sorting the input"

    On 22 Apr, 19:59, arnuld <> wrote:

    > 1st I think of creating an array of pointers of size 100 as this is the
    > maximum input I intend to take. I can create a fixed size array but in the
    > end I want my array to expand at run-time to fit the size of input. I am
    > not able to come up with anyting all all and doing:


    take a look at realloc(). Initally malloc() a block of pointers
    and when it fills up call realloc().

    >    char* arr_of_pointers[100];
    >
    > seems like a completely wrong idea as this is a static array. I want to
    > take the input and then decide how much memory I need and then malloc the
    > array of that size. I came up with K&R2 idea:
    >
    >    1.)   read and save the input lines till the user hits the EOF
    >    2.)   sort them
    >    3.)   print them
    >
    > I am pretty much confused on what to start with. Can I have your ideas in
    > solving this problem ? All I can think of is:
    >
    >   use sort algorithm from the standard library to sort the lines.
    >   print the lines using %s as argument in printf().


    or fputs()

    sounds fine to me. Which bit are you stuck on?


    --
    Nick Keighley
     
    Nick Keighley, Apr 22, 2008
    #1
    1. Advertising

  2. arnuld <> writes:

    >> On Tue, 22 Apr 2008 23:59:49 +0500, arnuld wrote:

    >
    >> 1st I think of creating an array of pointers of size 100 as this is the
    >> maximum input I intend to take. I can create a fixed size array but in the
    >> end I want my array to expand at run-time to fit the size of input. I am
    >> not able to come up with anyting all all and doing:
    >>
    >> char* arr_of_pointers[100];

    >
    >> ...[SNIP]....

    >
    >
    > I came up with the Static Version of this function with 1 error and I
    > can't seem to find a way either to remove that error or to convert it to a
    > dynamic version of the program:
    >
    >
    > /* write a program to read a set of lines from input and sort them
    > * and then print them.
    > *
    > * version 1.0
    > */
    >
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    > #include <string.h>
    >
    > enum MAXLINES { ARRSIZE = 100 };
    >
    > char* arr_of_ptr[ARRSIZE];
    > char arr_of_lines[ARRSIZE];


    I would not link these two sizes. You need two enum constants.

    > int readlines( char**, char*, const int max );
    > void printlines( char** );
    >
    >
    > /* main() will simply call the other functions to do the job */
    >
    > int main( void )
    > {
    > if( readlines( arr_of_ptr, arr_of_lines, ARRSIZE ) > 0 )
    > {
    > qsort( arr_of_ptr, ARRSIZE, sizeof( char* ) ); /* Line 26 */


    OK, I see you ask about this later.

    > printlines( arr_of_ptr );
    > }
    > else
    > {
    > fprintf( stderr, "error: out of memory\n" );
    > }
    >
    > return 0;
    > }
    >
    >
    > /* 1) read lines till we get the NULL,
    > * 2) store those lines into an array of characters <arr_of_lines>,
    > * 3) pointer of arry of pointers <arr_of_ptr> will point to the
    > * individual elements of array of characters <arr_of_lines>,
    > *
    > */
    >
    > int readlines( char* arr_of_ptr[], char arr_of_lines[], int max )


    The second parameter has a bad name. At best it is one line.

    > {
    > int num_lines;
    >
    > char temp_arr[ARRSIZE];
    >
    > num_lines = 0;
    >
    > while( fgets(temp_arr, max, stdin) )
    > {
    > strcpy( arr_of_lines, temp_arr );
    > *arr_of_ptr++ = arr_of_lines++;


    This can't work. You must malloc space for the line you have just
    read. There is nowhere else to put the line that will survive both
    the next execution of the loop and the return from this function.

    > ++num_lines;
    > }
    >
    > return num_lines;
    > }
    >
    >
    > /* it will simply print the lines pointed to by the elements of
    > * arrays of pointers <arr_of_ptr>.
    > *
    > */
    > void printlines( char* arr_of_ptr[] )
    > {
    > while( *arr_of_ptr != '\0' )


    Correct, but confusing. '\0' is a char constant equal to zero so it
    works, but I'd expect plain 0 or, better, NULL here.

    > {
    > puts( *arr_of_ptr++ );


    You will get extra newlines. puts adds one and fgets retains the
    newline from the input.

    > }
    > }
    > ================ OUTPUT ====================
    > [arnuld@raj C]$ gcc -ansi -pedantic -Wall -Wextra 5-7.c
    > 5-7.c: In function `main':
    > 5-7.c:27: error: too few arguments to function `qsort'
    > [arnuld@raj C]$
    >
    >
    >
    > I know that qsort needs a compare function and I found this in FAQ:
    >
    > http://www.c-faq.com/lib/qsort1.html
    >
    >
    > but a statement like: *(char * const *)p1
    >
    > is totally beyond my capability.


    I'd stick with reading the lines in first. Deal with sorting later.

    --
    Ben.
     
    Ben Bacarisse, Apr 22, 2008
    #2
    1. Advertising

  3. arnuld <> writes:

    >> On Tue, 22 Apr 2008 13:05:13 +0100, Ben Bacarisse wrote:

    >
    >
    >
    >> ...[SNIP]...

    >
    >> This can't work. You must malloc space for the line you have just
    >> read. There is nowhere else to put the line that will survive both
    >> the next execution of the loop and the return from this function.

    >
    >
    > I did not get what exactly you mean. That array is created already with
    > reserved space, then I am copying its contents to another place then I
    > don't care what fgets() puts into it on next call, because I will copy
    > that away too. It exists for temporary saving of input for single call to
    > while().


    In total your program had an array of 100 char pointers. One array of
    100 characters (the "global" one) and a local array of 100 characters.
    That just can't be enough "in general". Where are the characters of
    the second line stored?

    Did you intend that the whole file should fit into one 100 character
    array, with the each start of line pointer to by one of the 100
    character pointers? If that was your plan, then the error was one of
    detail -- you were not doing that, but your code could be corrected to
    do that. The trouble is that such fixed-size solutions are almost
    never worth getting right -- you need allocated storage when you don't
    know the data size in advance.

    > Though as you advised, I changed it to malloc but the "why the malloc" is
    > not clear to me.
    >
    >
    >
    >
    >> ..[SNIP].....
    >> I'd stick with reading the lines in first. Deal with sorting later.

    >
    > ok, I removed the sorting routines and any calls to it. This program now
    > compiles and runs with strange output:
    >
    >
    > /* write a program to read a set of lines from input and sort them
    > * and then print them.
    > *
    > * version 1.0
    > */
    >
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    > #include <string.h>
    >
    > enum MAXLINES { ARR_SIZE = 100, STR_SIZE = 1000 };
    >
    > char* arr_of_ptr[ARR_SIZE];
    > char arr_of_char[STR_SIZE];
    >
    > int readlines( char**, char*, const int max );
    > void printlines( char** );
    >
    >
    > /* main() will simply call the other functions to do the job */
    >
    > int main( void )
    > {
    > if( readlines( arr_of_ptr, arr_of_char, STR_SIZE ) > 0 )
    > {
    > /* qsort( arr_of_ptr, ARR_SIZE, sizeof( char* )); */
    > printlines( arr_of_ptr );
    > }
    > else
    > {
    > fprintf( stderr, "error: out of memory\n" );
    > }
    >
    > return 0;
    > }
    >
    >
    > /* 1) read lines till we get the NULL,
    > * 2) store those lines into an array of characters <arr_of_lines>,
    > * 3) pointer of arry of pointers <arr_of_ptr> will point to the
    > * individual elements of array of characters <arr_of_lines>,
    > *
    > */
    >
    > int readlines( char* arr_of_ptr[], char arr_of_char[], int max )
    > {
    > int num_lines;
    > char *p;
    >
    > p = malloc( max * sizeof( char* ));


    Not what I intended. I assumed you continue to use a local array for
    the line:

    char one_line[SOME_SIZE];

    > num_lines = 0;
    >
    > while( fgets(p, max, stdin) )


    and read into that:

    while( fgets(one_line, sizeof one_line, stdin) )

    > {


    and do the malloc here, to save the line. At this point we know how
    long it is (if we use strlen(one_line)) and we call allocate a copy
    the line.

    > strcpy( arr_of_char, p );
    > *arr_of_ptr++ = arr_of_char++;


    and we'd store the pointer in arr_or_ptr[num_lines] (I prefer that
    style to your *arr_of_ptr++ = ... one).

    > ++num_lines;
    > }
    >
    > return num_lines;
    > }


    --
    Ben.
     
    Ben Bacarisse, Apr 22, 2008
    #3
  4. On 23 Apr, 06:25, arnuld <> wrote:
    > > On Tue, 22 Apr 2008 13:05:13 +0100, Ben Bacarisse wrote:


    > > This can't work.  You must malloc space for the line you have just
    > > read.  There is nowhere else to put the line that will survive both
    > > the next execution of the loop and the return from this function.

    >
    > I did not get what exactly you mean.


    so I see! Say you have 10 lines you need 10 lumps
    of memory to store the lines.

    > That array is created already with
    > reserved space, then I am copying its contents to another place


    you read into the malloc()ed memory. Good. *Then* you copy it to
    static memory and ignore the malloc()ed memory!


    > then I
    > don't care what fgets() puts into it on next call, because I will copy
    > that away too. It exists for temporary saving of input for single call to
    > while().


    re-read your code it isn't doing what you think it is.


    > Though as you advised, I changed it to malloc but the "why the malloc" is
    > not clear to me.


    I don't understand

    <snip>

    > #include <stdio.h>
    > #include <stdlib.h>
    > #include <string.h>
    >
    > enum MAXLINES { ARR_SIZE = 100, STR_SIZE = 1000 };
    >
    > char*  arr_of_ptr[ARR_SIZE];
    > char   arr_of_char[STR_SIZE];
    >
    > int readlines(  char**, char*,  const int max );
    > void printlines( char** );


    you could avoid these by putting main() at the end


    > int main( void )
    > {
    >   if( readlines( arr_of_ptr, arr_of_char, STR_SIZE ) > 0 )
    >     {
    >       /*      qsort( arr_of_ptr, ARR_SIZE, sizeof( char* ));  */
    >       printlines( arr_of_ptr );      
    >     }
    >   else
    >     {
    >       fprintf( stderr, "error: out of memory\n" );


    well no. It might be an empty file


    >     }
    >
    >   return 0;
    >
    > }
    >
    > /* 1) read lines till we get the NULL,
    >  * 2) store those lines into an array of characters <arr_of_lines>,
    >  * 3) pointer of arry of pointers <arr_of_ptr> will point to the
    >  *    individual elements of array of characters <arr_of_lines>,
    >  *
    >  */
    >
    > int readlines( char* arr_of_ptr[], char arr_of_char[], int max )
    > {
    >   int num_lines;
    >   char *p;
    >
    >   p = malloc( max * sizeof( char* ));


    don't you mean sizeof(char)? Or since sizeof(char)
    is 1 just omit it. You don't check the return
    value of malloc(). Your malloc() should be in the loop.


    >   num_lines = 0;
    >
    >   while( fgets(p, max, stdin) )


    you read it into the malloced buffer

    >     {
    >       strcpy( arr_of_char, p );


    then you copy to a static buffer. Why?


    >       *arr_of_ptr++ = arr_of_char++;


    what does this do? When the loop ends

    aop[0] = aoc[0]
    aop[1] = aoc[1]
    aop[2] = aoc[2]

    suppose aoc contains "ao...love"
    then your print routine will print

    ao...love
    o...love
    ...love


    >       ++num_lines;
    >     }
    >
    >   return num_lines;
    >
    > }
    >
    > /* it will simply print the lines pointed to by the elements of
    >  * arrays of pointers <arr_of_ptr>.
    >  *
    >  */
    > void printlines( char* arr_of_ptr[] )
    > {
    >   printf("\n-------------------------\n");
    >   while( *arr_of_ptr )
    >     {
    >       printf("%s", *arr_of_ptr++ );
    >     }
    >
    > }
    >
    > =========== OUTPUT ==============
    > [arnuld@raj C]$ gcc -ansi -pedantic -Wall -Wextra 5-7.c
    > [arnuld@raj C]$ ./a.out
    > and
    > oye
    > ...love
    >
    > -------------------------
    > ao...love
    > o...love
    > ...love



    --
    Nick Keighley
     
    Nick Keighley, Apr 22, 2008
    #4
  5. arnuld <> writes:

    <snip>
    > you meant this ?
    >
    >
    > int readlines( char* arr_of_ptr[], const int max )
    > {
    > int num_lines, size_arr;
    > char *p;
    > char temp_arr[STR_SIZE];
    >
    > num_lines = 0;
    >
    > while( fgets(temp_arr, max, stdin) && num_lines < max )
    > {
    > size_arr = strlen( temp_arr );
    > if( (p = malloc( size_arr * sizeof( char* ))) )


    You need size_arr + 1. You are storing chars, not char *s.

    > {
    > strcpy( p, temp_arr );
    > *arr_of_ptr++ = p;
    > ++num_lines;
    > }
    >
    > }
    >
    > return num_lines;
    > }
    >
    >
    >> and we'd store the pointer in arr_or_ptr[num_lines] (I prefer that
    >> style to your *arr_of_ptr++ = ... one).

    >
    >
    > That's the style I want to use but I don't use it as that lies to me
    > about the very basic fact of C. At some point I will also stop using []
    > notation in function arguments as it fakes the array, it lies that it is
    > not a pointer, that it is a box of characters we call array and we are
    > using it directly but we are not, in fact, it is a pointer that is
    > manipulating the array and hence this distinction is the source of most
    > troubles I have and this trouble is intensively painful than the troubles
    > I get by not using array indexing.


    Sorry, I can't follow that. It was a matter of style not correctness,
    so I am not sure it is worth pursuing.

    --
    Ben.
     
    Ben Bacarisse, Apr 22, 2008
    #5
  6. arnuld wrote:
    >> On Tue, 22 Apr 2008 15:50:11 +0100, Ben Bacarisse wrote:

    >
    >>> arnuld <> writes:
    >>> while( fgets(temp_arr, max, stdin) && num_lines < max )
    >>> {
    >>> size_arr = strlen( temp_arr );
    >>> if( (p = malloc( size_arr * sizeof( char* ))) )

    >
    >> You need size_arr + 1. You are storing chars, not char *s.

    >
    >
    > and what I am supposed to do with last element ?

    You need It for the string terminating \0.
    strlen gives the lengh without the terminating \0, so you need to add it to
    the size you malloc

    > I think NULL should be the last element but I can't find a way
    > to add it.

    \0, not NULL and the "strcpy( p, temp_arr );" in your next line whill do
    that for you.

    Bye, Jojo
     
    Joachim Schmitz, Apr 22, 2008
    #6
  7. arnuld <> writes:

    >> On Tue, 22 Apr 2008 15:50:11 +0100, Ben Bacarisse wrote:

    >
    >>> arnuld <> writes:
    >>> while( fgets(temp_arr, max, stdin) && num_lines < max )
    >>> {
    >>> size_arr = strlen( temp_arr );
    >>> if( (p = malloc( size_arr * sizeof( char* ))) )

    >
    >> You need size_arr + 1. You are storing chars, not char *s.

    >
    > and what I am supposed to do with last element ?
    >
    > I think NULL should be the last element but I can't find a way
    > to add it.


    the strcpy (now snipped from the quote) copies the string including
    the final '\0' bytes. That is what the +1 is for.

    --
    Ben.
     
    Ben Bacarisse, Apr 22, 2008
    #7
  8. Nick Keighley

    arnuld Guest

    1st I think of creating an array of pointers of size 100 as this is the
    maximum input I intend to take. I can create a fixed size array but in the
    end I want my array to expand at run-time to fit the size of input. I am
    not able to come up with anyting all all and doing:

    char* arr_of_pointers[100];

    seems like a completely wrong idea as this is a static array. I want to
    take the input and then decide how much memory I need and then malloc the
    array of that size. I came up with K&R2 idea:


    1.) read and save the input lines till the user hits the EOF
    2.) sort them
    3.) print them

    I am pretty much confused on what to start with. Can I have your ideas in
    solving this problem ? All I can think of is:


    use sort algorithm from the standard library to sort the lines.
    print the lines using %s as argument in printf().



    --
    http://lispmachine.wordpress.com/
    my email ID is at the above address
     
    arnuld, Apr 22, 2008
    #8
  9. Nick Keighley

    arnuld Guest

    > On Tue, 22 Apr 2008 23:59:49 +0500, arnuld wrote:

    > 1st I think of creating an array of pointers of size 100 as this is the
    > maximum input I intend to take. I can create a fixed size array but in the
    > end I want my array to expand at run-time to fit the size of input. I am
    > not able to come up with anyting all all and doing:
    >
    > char* arr_of_pointers[100];


    > ...[SNIP]....



    I came up with the Static Version of this function with 1 error and I
    can't seem to find a way either to remove that error or to convert it to a
    dynamic version of the program:


    /* write a program to read a set of lines from input and sort them
    * and then print them.
    *
    * version 1.0
    */


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

    enum MAXLINES { ARRSIZE = 100 };

    char* arr_of_ptr[ARRSIZE];
    char arr_of_lines[ARRSIZE];

    int readlines( char**, char*, const int max );
    void printlines( char** );


    /* main() will simply call the other functions to do the job */

    int main( void )
    {
    if( readlines( arr_of_ptr, arr_of_lines, ARRSIZE ) > 0 )
    {
    qsort( arr_of_ptr, ARRSIZE, sizeof( char* ) ); /* Line 26 */
    printlines( arr_of_ptr );
    }
    else
    {
    fprintf( stderr, "error: out of memory\n" );
    }

    return 0;
    }


    /* 1) read lines till we get the NULL,
    * 2) store those lines into an array of characters <arr_of_lines>,
    * 3) pointer of arry of pointers <arr_of_ptr> will point to the
    * individual elements of array of characters <arr_of_lines>,
    *
    */

    int readlines( char* arr_of_ptr[], char arr_of_lines[], int max )
    {
    int num_lines;

    char temp_arr[ARRSIZE];

    num_lines = 0;

    while( fgets(temp_arr, max, stdin) )
    {
    strcpy( arr_of_lines, temp_arr );
    *arr_of_ptr++ = arr_of_lines++;
    ++num_lines;
    }

    return num_lines;
    }


    /* it will simply print the lines pointed to by the elements of
    * arrays of pointers <arr_of_ptr>.
    *
    */
    void printlines( char* arr_of_ptr[] )
    {
    while( *arr_of_ptr != '\0' )
    {
    puts( *arr_of_ptr++ );
    }
    }
    ================ OUTPUT ====================
    [arnuld@raj C]$ gcc -ansi -pedantic -Wall -Wextra 5-7.c
    5-7.c: In function `main':
    5-7.c:27: error: too few arguments to function `qsort'
    [arnuld@raj C]$



    I know that qsort needs a compare function and I found this in FAQ:

    http://www.c-faq.com/lib/qsort1.html


    but a statement like: *(char * const *)p1

    is totally beyond my capability.




    --
    http://lispmachine.wordpress.com/
    my email ID is at the above address
     
    arnuld, Apr 23, 2008
    #9
  10. Nick Keighley

    arnuld Guest

    > On Tue, 22 Apr 2008 13:05:13 +0100, Ben Bacarisse wrote:



    > ...[SNIP]...


    > This can't work. You must malloc space for the line you have just
    > read. There is nowhere else to put the line that will survive both
    > the next execution of the loop and the return from this function.



    I did not get what exactly you mean. That array is created already with
    reserved space, then I am copying its contents to another place then I
    don't care what fgets() puts into it on next call, because I will copy
    that away too. It exists for temporary saving of input for single call to
    while().

    Though as you advised, I changed it to malloc but the "why the malloc" is
    not clear to me.




    > ..[SNIP].....
    > I'd stick with reading the lines in first. Deal with sorting later.


    ok, I removed the sorting routines and any calls to it. This program now
    compiles and runs with strange output:


    /* write a program to read a set of lines from input and sort them
    * and then print them.
    *
    * version 1.0
    */


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

    enum MAXLINES { ARR_SIZE = 100, STR_SIZE = 1000 };

    char* arr_of_ptr[ARR_SIZE];
    char arr_of_char[STR_SIZE];

    int readlines( char**, char*, const int max );
    void printlines( char** );


    /* main() will simply call the other functions to do the job */

    int main( void )
    {
    if( readlines( arr_of_ptr, arr_of_char, STR_SIZE ) > 0 )
    {
    /* qsort( arr_of_ptr, ARR_SIZE, sizeof( char* )); */
    printlines( arr_of_ptr );
    }
    else
    {
    fprintf( stderr, "error: out of memory\n" );
    }

    return 0;
    }


    /* 1) read lines till we get the NULL,
    * 2) store those lines into an array of characters <arr_of_lines>,
    * 3) pointer of arry of pointers <arr_of_ptr> will point to the
    * individual elements of array of characters <arr_of_lines>,
    *
    */

    int readlines( char* arr_of_ptr[], char arr_of_char[], int max )
    {
    int num_lines;
    char *p;

    p = malloc( max * sizeof( char* ));

    num_lines = 0;

    while( fgets(p, max, stdin) )
    {
    strcpy( arr_of_char, p );
    *arr_of_ptr++ = arr_of_char++;
    ++num_lines;
    }

    return num_lines;
    }




    /* it will simply print the lines pointed to by the elements of
    * arrays of pointers <arr_of_ptr>.
    *
    */
    void printlines( char* arr_of_ptr[] )
    {
    printf("\n-------------------------\n");
    while( *arr_of_ptr )
    {
    printf("%s", *arr_of_ptr++ );
    }
    }


    =========== OUTPUT ==============
    [arnuld@raj C]$ gcc -ansi -pedantic -Wall -Wextra 5-7.c
    [arnuld@raj C]$ ./a.out
    and
    oye
    ....love

    -------------------------
    ao...love
    o...love
    ....love
    [arnuld@raj C]$




    --
    http://lispmachine.wordpress.com/
    my email ID is at the above address
     
    arnuld, Apr 23, 2008
    #10
  11. Nick Keighley

    arnuld Guest

    > On Tue, 22 Apr 2008 14:18:26 +0100, Ben Bacarisse wrote:


    > In total your program had an array of 100 char pointers. One array of
    > 100 characters (the "global" one) and a local array of 100 characters.
    > That just can't be enough "in general". Where are the characters of
    > the second line stored?


    :-O



    > and read into that:
    >
    > while( fgets(one_line, sizeof one_line, stdin) )


    > and do the malloc here, to save the line. At this point we know how
    > long it is (if we use strlen(one_line)) and we call allocate a copy
    > the line.



    you meant this ?


    int readlines( char* arr_of_ptr[], const int max )
    {
    int num_lines, size_arr;
    char *p;
    char temp_arr[STR_SIZE];

    num_lines = 0;

    while( fgets(temp_arr, max, stdin) && num_lines < max )
    {
    size_arr = strlen( temp_arr );
    if( (p = malloc( size_arr * sizeof( char* ))) )
    {
    strcpy( p, temp_arr );
    *arr_of_ptr++ = p;
    ++num_lines;
    }

    }

    return num_lines;
    }


    > and we'd store the pointer in arr_or_ptr[num_lines] (I prefer that
    > style to your *arr_of_ptr++ = ... one).



    That's the style I want to use but I don't use it as that lies to me
    about the very basic fact of C. At some point I will also stop using []
    notation in function arguments as it fakes the array, it lies that it is
    not a pointer, that it is a box of characters we call array and we are
    using it directly but we are not, in fact, it is a pointer that is
    manipulating the array and hence this distinction is the source of most
    troubles I have and this trouble is intensively painful than the troubles
    I get by not using array indexing.





    --
    http://lispmachine.wordpress.com/
    my email ID is at the above address
     
    arnuld, Apr 23, 2008
    #11
  12. Nick Keighley

    arnuld Guest

    > On Tue, 22 Apr 2008 15:50:11 +0100, Ben Bacarisse wrote:

    >> arnuld <> writes:
    >> while( fgets(temp_arr, max, stdin) && num_lines < max )
    >> {
    >> size_arr = strlen( temp_arr );
    >> if( (p = malloc( size_arr * sizeof( char* ))) )


    > You need size_arr + 1. You are storing chars, not char *s.



    and what I am supposed to do with last element ?

    I think NULL should be the last element but I can't find a way
    to add it.


    > Sorry, I can't follow that. It was a matter of style not correctness,
    > so I am not sure it is worth pursuing.


    okay :)


    --
    http://lispmachine.wordpress.com/
    my email ID is at the above address
     
    arnuld, Apr 23, 2008
    #12
  13. Nick Keighley

    arnuld Guest

    > On Tue, 22 Apr 2008 13:05:13 +0100, Ben Bacarisse wrote:



    > I would not link these two sizes. You need two enum constants.


    it is done.


    > The second parameter has a bad name. At best it is one line.


    sorry, my mistake



    > I'd stick with reading the lines in first. Deal with sorting later.



    okay, I am done with reading and printing lines now. It is working now, I
    need to understand the sorting part now:


    /* write a program to read a set of lines from input and sort them
    * and then print them.
    *
    * version 1.0
    */


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

    enum MAXLINES { ARR_SIZE = 100, STR_SIZE = 1000 };

    char* arr_of_ptr[ARR_SIZE];
    char arr_of_char[STR_SIZE];

    int readlines( char**, const int );
    void printlines( char** );


    /* main() will simply call the other functions to do the job */

    int main( void )
    {
    if( readlines( arr_of_ptr, ARR_SIZE ) > 0 )
    {
    /* qsort( arr_of_ptr, ARR_SIZE, sizeof( char* )); */
    printlines( arr_of_ptr );
    }
    else
    {
    fprintf( stderr, "error: out of memory\n" );
    }

    return 0;
    }


    /* 1) read lines till we get the NULL,
    * 2) store those lines into an array of characters <arr_of_lines>,
    * 3) pointer of arry of pointers <arr_of_ptr> will point to the
    * individual elements of array of characters <arr_of_lines>,
    *
    */

    int readlines( char* arr_of_ptr[], const int max )
    {
    char *p, **p_arrptr;
    int num_lines, size_arr;
    char temp_arr[STR_SIZE];

    num_lines = 0;
    p_arrptr = arr_of_ptr;

    while( fgets(temp_arr, max, stdin) && num_lines < max )
    {
    size_arr = strlen( temp_arr ) + 1;
    if( (p = malloc( size_arr * sizeof( char ))) )
    {
    strcpy( p, temp_arr );
    *p_arrptr++ = p;
    ++num_lines;
    }

    }

    return num_lines;
    }




    /* it will simply print the lines pointed to by the elements of
    * arrays of pointers <arr_of_ptr>.
    *
    */
    void printlines( char* arr_of_ptr[] )
    {
    printf("\n-------------------------\n");
    while( *arr_of_ptr )
    {
    printf("%s", *arr_of_ptr++ );
    }
    }

    ============= OUTPUT ===================
    /home/arnuld/programs/C $ gcc -ansi -pedantic -Wall -Wextra 5-7.c
    /home/arnuld/programs/C $ ./a.out
    Ben & Richard
    both are helping
    C newbie.... arnuld

    -------------------------
    Ben & Richard
    both are helping
    C newbie.... arnuld
    /home/arnuld/programs/C $







    --
    http://lispmachine.wordpress.com/
    my email ID is at the above address
     
    arnuld, Apr 23, 2008
    #13
  14. arnuld <> writes:

    > On Tue, 22 Apr 2008 13:05:13 +0100, Ben Bacarisse wrote:
    >> I'd stick with reading the lines in first. Deal with sorting later.

    >
    > okay, I am done with reading and printing lines now. It is working
    > now,


    Sorry, not quite.

    > I need to understand the sorting part now:


    I think you need to show your best attempt at the sort call and people
    will help you get the details right.

    > /* write a program to read a set of lines from input and sort them
    > * and then print them.
    > *
    > * version 1.0
    > */


    > enum MAXLINES { ARR_SIZE = 100, STR_SIZE = 1000 };
    >
    > char* arr_of_ptr[ARR_SIZE];
    > char arr_of_char[STR_SIZE];


    This second array seem not to be used now (that is as I would expect)
    so you should get rid of it.

    > if( readlines( arr_of_ptr, ARR_SIZE ) > 0 )


    > int readlines( char* arr_of_ptr[], const int max )
    > {
    > char *p, **p_arrptr;
    > int num_lines, size_arr;
    > char temp_arr[STR_SIZE];
    >
    > num_lines = 0;
    > p_arrptr = arr_of_ptr;
    >
    > while( fgets(temp_arr, max, stdin) && num_lines < max )

    ^^^?

    Safe (because max happens to be less that STR_SIZE) but not correct.

    > {
    > size_arr = strlen( temp_arr ) + 1;
    > if( (p = malloc( size_arr * sizeof( char ))) )


    You can omit sizeof(char). It is 1 by definition. I can see why some
    people might want a size there, but if you are one of them then you
    should use the c.l.c-approved idiom:

    if( (p = malloc(size_arr * sizeof *p)) )

    > {
    > strcpy( p, temp_arr );
    > *p_arrptr++ = p;
    > ++num_lines;
    > }
    >
    > }
    >
    > return num_lines;
    > }


    --
    Ben.
     
    Ben Bacarisse, Apr 23, 2008
    #14
  15. Nick Keighley

    santosh Guest

    arnuld wrote:

    >> On Wed, 23 Apr 2008 13:17:26 +0100, Ben Bacarisse wrote:

    >
    >>> arnuld wrote:
    >>> size_arr = strlen( temp_arr ) + 1;
    >>> if( (p = malloc( size_arr * sizeof( char ))) )

    >
    >> You can omit sizeof(char). It is 1 by definition. I can see why
    >> some people might want a size there, but if you are one of them then
    >> you should use the c.l.c-approved idiom:
    >>
    >> if( (p = malloc(size_arr * sizeof *p)) )

    >
    > where is "p" pointing to ? nowhere . so you can't dereference it yet.


    That's perfectly legal. Sizeof is a compile time operator and no actual
    deferencing of the pointer is done.
     
    santosh, Apr 24, 2008
    #15
  16. Nick Keighley

    arnuld Guest

    > On Wed, 23 Apr 2008 13:17:26 +0100, Ben Bacarisse wrote:

    >> arnuld <> writes:


    >> okay, I am done with reading and printing lines now. It is working
    >> now,


    > Sorry, not quite.


    I have shown you the output and it seems ok to me. Did you find something
    wrong ?



    >> I need to understand the sorting part now:


    > I think you need to show your best attempt at the sort call and people
    > will help you get the details right.



    I can't understand the 13.8 of FAQs: http://c-faq.com/lib/qsort1.html

    /* compare strings via pointers */
    int pstrcmp(const void *p1, const void *p2)
    {
    return strcmp(*(char * const *)p1, *(char * const *)p2);
    }


    parameters are made void* but in fact we are passing char**, which is 2 levels of
    indirection. and what about the cast:

    (char* const*)p1


    we are casting a <pointer to void> to <pointer to a const pointer to char>
    , right ?



    >> char* arr_of_ptr[ARR_SIZE];
    >> char arr_of_char[STR_SIZE];


    > This second array seem not to be used now (that is as I would expect)
    > so you should get rid of it.


    okay


    >> while( fgets(temp_arr, max, stdin) && num_lines < max )

    > ^^^?
    >
    > Safe (because max happens to be less that STR_SIZE) but not correct.



    incorrect ?


    If the user enters the 1001 characters then program will crash or behave
    strangely or something but I can't do anything here as the array-size has
    to be there at compile-time. Even if I do malloc() for array then for user
    input I use fgets() I will still need a limit to read the characters.




    >> if( (p = malloc( size_arr * sizeof( char ))) )


    > You can omit sizeof(char). It is 1 by definition.


    you mean, by default, if I type: <malloc( size_arr )> then it will be
    converted to <malloc(size_arr * 1)> ?




    > I can see why some
    > people might want a size there, but if you are one of them then you
    > should use the c.l.c-approved idiom:
    >
    > if( (p = malloc(size_arr * sizeof *p)) )


    okay




    --
    http://lispmachine.wordpress.com/
    my email ID is at the above address
     
    arnuld, Apr 24, 2008
    #16
  17. On Fri, 25 Apr 2008 01:58:51 +0500, arnuld <> wrote:

    >> On Wed, 23 Apr 2008 13:17:26 +0100, Ben Bacarisse wrote:

    >
    >>> arnuld wrote:
    >>> size_arr = strlen( temp_arr ) + 1;
    >>> if( (p = malloc( size_arr * sizeof( char ))) )

    >
    >> You can omit sizeof(char). It is 1 by definition. I can see why some
    >> people might want a size there, but if you are one of them then you
    >> should use the c.l.c-approved idiom:
    >>
    >> if( (p = malloc(size_arr * sizeof *p)) )

    >
    >where is "p" pointing to ? nowhere . so you can't dereference it yet.


    Since sizeof does not evaluate its operand (except for VLA), the *p
    does not involve a dereference. *p simply identifies the type that
    sizeof should operate on.


    Remove del for email
     
    Barry Schwarz, Apr 24, 2008
    #17
  18. On Fri, 25 Apr 2008 02:04:45 +0500, arnuld <> wrote:

    >I have tried the strcmp function from FAQ:
    >
    > http://c-faq.com/lib/qsort1.html
    >
    >it fails to do its job. It Segfaults :( . If I remove its call from the
    >program, my program compiles and runs fine:


    Is sorting important to your program or not? If not, leave it out. If
    it is, then your program does not run fine without it. The output
    will not be sorted.

    >
    >
    > /* write a program to read a set of lines from input and sort them
    > * and then print them.


    One might infer that sorting is important.

    > *
    > * version 1.0
    > */
    >
    >
    >#include <stdio.h>
    >#include <stdlib.h>
    >#include <string.h>
    >
    >enum MAXLINES { ARR_SIZE = 100, STR_SIZE = 1000 };
    >
    >char* arr_of_ptr[ARR_SIZE];
    >/* char arr_of_char[STR_SIZE]; */
    >
    >int readlines( char**, const int );
    >void printlines( char** );
    >int p_strcmp( const void*, const void* );
    >
    >
    >/* main() will simply call the other functions to do the job */
    >int main( void )
    >{
    > if( readlines( arr_of_ptr, ARR_SIZE ) > 0 )
    > {
    > qsort( arr_of_ptr, ARR_SIZE, sizeof( char* ), p_strcmp );


    The second argument to qsort is the number of array elements to
    process. While there are ARR_SIZE elements, most of them contain NULL
    and should not be processed. readlines told you how many elements to
    process but you threw that information away.

    > printlines( arr_of_ptr );
    > }
    >
    >
    > return 0;
    >}
    >
    >
    >/* 1) read lines till we get the NULL,
    > * 2) store those lines into an array of characters <arr_of_lines>,
    > * 3) pointer of arry of pointers <arr_of_ptr> will point to the
    > * individual elements of array of characters <arr_of_lines>,
    > *
    > */
    >
    >int readlines( char* arr_of_ptr[], const int max )
    >{
    > char *p, **p_arrptr;
    > int num_lines, size_arr;
    > char temp_arr[STR_SIZE];
    >
    > num_lines = 0;
    > p_arrptr = arr_of_ptr;
    >
    > while( fgets(temp_arr, max, stdin) && num_lines < max )


    People have already told you that max is not appropriate in the call
    to fgets. If you won't listen, why post?

    > {
    > size_arr = strlen( temp_arr ) + 1;


    It is a nit but this will include the '\n' that fgets inserts for a
    line shorter than the buffer. Most seem to think it is worth
    eliminating.

    > if( (p = malloc( size_arr * sizeof( char ))) )
    > {
    > strcpy( p, temp_arr );
    > *p_arrptr++ = p;
    > ++num_lines;
    > }
    >
    > }
    >
    > return num_lines;
    >}
    >
    >
    >
    >/* it will simply print the lines pointed to by the elements of
    > * arrays of pointers <arr_of_ptr>.
    > *
    > */
    >void printlines( char* arr_of_ptr[] )
    >{
    > printf("\n-------------------------\n");
    > while( *arr_of_ptr )
    > {
    > printf("%s", *arr_of_ptr++ );
    > }
    >}
    >
    >
    >/* compare 2 strings using pointers */
    >int p_strcmp( const void* pv1, const void* pv2 )
    >{
    > return strcmp( *(char* const*)pv1, *(char* const*)pv2 );


    When either v1 or v2 is NULL, this invoked undefined behavior. A
    segfault is one of the nicer manifestations of same.

    >}



    Remove del for email
     
    Barry Schwarz, Apr 24, 2008
    #18
  19. Nick Keighley

    Ian Collins Guest

    arnuld wrote:
    >> On Thu, 24 Apr 2008 10:20:07 +0000, Richard Heathfield wrote:

    >
    >
    >> He isn't dereferencing it: sizeof does not evaluate its operand (except
    >> for one tiny corner-case in C99 that doesn't apply here), so no
    >> dereferencing is taking place.

    >
    > so, sizeof() operator does not evaluate its operands. It finds the number
    > of bytes without evaluating anything ?
    >

    It is evaluating the size of a type, at compile time.

    --
    Ian Collins.
     
    Ian Collins, Apr 24, 2008
    #19
  20. In article <>,
    arnuld <> wrote:

    >> He isn't dereferencing it: sizeof does not evaluate its operand (except
    >> for one tiny corner-case in C99 that doesn't apply here), so no
    >> dereferencing is taking place.


    >so, sizeof() operator does not evaluate its operands. It finds the number
    >of bytes without evaluating anything ?


    In effect, it instructs the compiler to find the number of bytes
    used by the argument. That depends on the *type* of the argument,
    not its value. And you don't need to evaluate an expression to
    determine its type: if a and b are ints, a+b is an int regardless
    of the values of a and b; if x is an array of doubles, x[5] is always
    a double, and so on.

    The compiler does some calculations to determine the type and hence
    the size, so you could say it evaluates *something*, but it doesn't
    evaluate the argument itself.

    -- Richard
    --
    :wq
     
    Richard Tobin, Apr 24, 2008
    #20
    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. arnuld

    sorting the input

    arnuld, Sep 10, 2008, in forum: C++
    Replies:
    16
    Views:
    980
    Hendrik Schober
    Sep 25, 2008
  2. Replies:
    2
    Views:
    1,476
    James Kanze
    Jul 6, 2010
  3. Jason
    Replies:
    0
    Views:
    406
    Jason
    Oct 4, 2006
  4. Tom Kirchner

    sorting by multiple criterias (sub-sorting)

    Tom Kirchner, Oct 11, 2003, in forum: Perl Misc
    Replies:
    3
    Views:
    501
    Michael Budash
    Oct 11, 2003
  5. Íéêüëáïò Êïýñáò

    Sorting a set works, sorting a dictionary fails ?

    Íéêüëáïò Êïýñáò, Jun 10, 2013, in forum: Python
    Replies:
    12
    Views:
    168
    Ulrich Eckhardt
    Jun 10, 2013
Loading...

Share This Page