473,397 Members | 1,950 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

sorting the input

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

Jun 27 '08 #1
77 3264
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_ptrwill 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

Jun 27 '08 #2
please include the subject in the body of your email:

"sorting the input"

On 22 Apr, 19:59, arnuld <GoogleGroupsisFull0fS...@gmail.comwrote:
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

Jun 27 '08 #3
arnuld <Go**********************@gmail.comwrites:
>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_ptrwill 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.
Jun 27 '08 #4
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_ptrwill 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

Jun 27 '08 #5
arnuld <Go**********************@gmail.comwrites:
>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_ptrwill 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.
Jun 27 '08 #6
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

Jun 27 '08 #7
On 23 Apr, 06:25, arnuld <GoogleGroupsisFull0fS...@gmail.comwrote:
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_ptrwill 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
Jun 27 '08 #8
arnuld <Go**********************@gmail.comwrites:

<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.
Jun 27 '08 #9
On Tue, 22 Apr 2008 15:50:11 +0100, Ben Bacarisse wrote:
>arnuld <Go**********************@gmail.comwrites:
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

Jun 27 '08 #10
arnuld wrote:
>On Tue, 22 Apr 2008 15:50:11 +0100, Ben Bacarisse wrote:
>>arnuld <Go**********************@gmail.comwrites:
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
Jun 27 '08 #11
arnuld <Go**********************@gmail.comwrites:
>On Tue, 22 Apr 2008 15:50:11 +0100, Ben Bacarisse wrote:
>>arnuld <Go**********************@gmail.comwrites:
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.
Jun 27 '08 #12
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_ptrwill 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

Jun 27 '08 #13
arnuld <Go**********************@gmail.comwrites:
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.
Jun 27 '08 #14
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];

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 ?
That is my idea of a linked list problem.

/* BEGIN sort_input.c */

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

typedef struct list_node {
struct list_node *next;
void *data;
} list_type;

int lencomp(const list_type *a, const list_type *b);
int str_cmp(const list_type *a, const list_type *b);
int get_line(char **lineptr, size_t *n, FILE *stream);
int list_fputs(const list_type *node, FILE *stream);
list_type *list_append
(list_type **head, list_type *tail, void *data, size_t size);
void list_free(list_type *node, void (*free_data)(void *));
list_type *list_sort(list_type *head,
int (*compar)(const list_type *, const list_type *));
list_type *sort_node(list_type *head,
int (*compar)(const list_type *, const list_type *));
list_type *split_list(list_type *head);
list_type *merge_lists(list_type *head, list_type *tail,
int (*compar)(const list_type *, const list_type *));

int main(void)
{
int rc;
list_type *head = NULL;
list_type *tail = NULL;
char *buff = NULL;
size_t size = 0;
long unsigned line_count = 0;

puts("/* BEGIN sort_input.c output */\n");
puts("This program makes and prints a list of all the lines\n"
"of text entered from standard input.\n"
"Just hit the Enter key to end,\n"
"or enter any line of characters to continue.");
while ((rc = get_line(&buff, &size, stdin)) 1) {
++line_count;
tail = list_append(&head, tail, buff, rc);
if (tail == NULL) {
break;
}
puts("\nJust hit the Enter key to end,\n"
"or enter any line of characters to continue");
}
free(buff);
printf("%lu lines of text were entered.\n", line_count);
puts("They are:");
list_fputs(head, stdout);
puts("\nStable sorted by length, the lines are:");
head = list_sort(head, lencomp);
list_fputs(head, stdout);
puts("\nSorted by strcmp, they are:");
head = list_sort(head, str_cmp);
list_fputs(head, stdout);
list_free(head, free);
puts("\n/* END sort_input.c output */");
return 0;
}

int lencomp(const list_type *a, const list_type *b)
{
const size_t a_len = strlen(a -data);
const size_t b_len = strlen(b -data);

return b_len a_len ? -1 : b_len != a_len;
}

int str_cmp(const list_type *a, const list_type *b)
{
return strcmp(a -data, b -data);
}

int get_line(char **lineptr, size_t *n, FILE *stream)
{
int rc;
void *p;
size_t count;

count = 0;
while ((rc = getc(stream)) != EOF
|| !feof(stream) && !ferror(stream))
{
++count;
if (count == (size_t)-2) {
if (rc != '\n') {
(*lineptr)[count] = '\0';
(*lineptr)[count - 1] = (char)rc;
} else {
(*lineptr)[count - 1] = '\0';
}
break;
}
if (count + 2 *n) {
p = realloc(*lineptr, count + 2);
if (p == NULL) {
if (*n count) {
if (rc != '\n') {
(*lineptr)[count] = '\0';
(*lineptr)[count - 1] = (char)rc;
} else {
(*lineptr)[count - 1] = '\0';
}
} else {
if (*n != 0) {
**lineptr = '\0';
}
ungetc(rc, stream);
}
count = 0;
break;
}
*lineptr = p;
*n = count + 2;
}
if (rc != '\n') {
(*lineptr)[count - 1] = (char)rc;
} else {
(*lineptr)[count - 1] = '\0';
break;
}
}
if (rc != EOF || !feof(stream) && !ferror(stream)) {
rc = INT_MAX count ? count : INT_MAX;
} else {
if (*n count) {
(*lineptr)[count] = '\0';
}
}
return rc;
}

int list_fputs(const list_type *node, FILE *stream)
{
int rc = 0;

while (node != NULL
&& (rc = fputs(node -data, stream)) != EOF
&& (rc = putc('\n', stream)) != EOF)
{
node = node -next;
}
return rc;
}

list_type *list_append
(list_type **head, list_type *tail, void *data, size_t size)
{
list_type *node;

node = malloc(sizeof *node);
if (node != NULL) {
node -next = NULL;
node -data = malloc(size);
if (node -data != NULL) {
memcpy(node -data, data, size);
if (*head != NULL) {
tail -next = node;
} else {
*head = node;
}
} else {
free(node);
node = NULL;
}
}
return node;
}

void list_free(list_type *node, void (*free_data)(void *))
{
list_type *next_node;

while (node != NULL) {
next_node = node -next;
free_data(node -data);
free(node);
node = next_node;
}
}

list_type *list_sort(list_type *head,
int (*compar)(const list_type *, const list_type *))
{
return head != NULL ? sort_node(head, compar) : head;
}

list_type *sort_node(list_type *head,
int (*compar)(const list_type *, const list_type *))
{
list_type *tail;

if (head -next != NULL) {
tail = split_list(head);
tail = sort_node(tail, compar);
head = sort_node(head, compar);
head = merge_lists(head, tail, compar);
}
return head;
}

list_type *split_list(list_type *head)
{
list_type *tail;

tail = head -next;
while ((tail = tail -next) != NULL
&& (tail = tail -next) != NULL)
{
head = head -next;
}
tail = head -next;
head -next = NULL;
return tail;
}

list_type *merge_lists(list_type *head, list_type *tail,
int (*compar)(const list_type *, const list_type *))
{
list_type *list, *sorted, **node;

node = compar(head, tail) 0 ? &tail : &head;
list = sorted = *node;
*node = sorted -next;
while (*node != NULL) {
node = compar(head, tail) 0 ? &tail : &head;
sorted -next = *node;
sorted = *node;
*node = sorted -next;
}
sorted -next = tail != NULL ? tail : head;
return list;
}

/* END get_line.c */
Jun 27 '08 #15
On Wed, 23 Apr 2008 13:17:26 +0100, Ben Bacarisse wrote:
>arnuld <Go**********************@gmail.comwrites:
>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 voidto <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

Jun 27 '08 #16
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.
--
http://lispmachine.wordpress.com/
my email ID is at the above address

Jun 27 '08 #17
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:
/* 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** );
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 );
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_ptrwill 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++ );
}
}
/* compare 2 strings using pointers */
int p_strcmp( const void* pv1, const void* pv2 )
{
return strcmp( *(char* const*)pv1, *(char* const*)pv2 );
}

Jun 27 '08 #18
arnuld said:
>On Wed, 23 Apr 2008 13:17:26 +0100, Ben Bacarisse wrote:
<snip>
> if( (p = malloc(size_arr * sizeof *p)) )

where is "p" pointing to ? nowhere . so you can't dereference it yet.
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.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #19
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.

Jun 27 '08 #20
On Fri, 25 Apr 2008 01:58:51 +0500, arnuld <No****@NoPain.comwrote:
>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
Jun 27 '08 #21
On Fri, 25 Apr 2008 02:04:45 +0500, arnuld <No****@NoPain.comwrote:
>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_ptrwill 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
Jun 27 '08 #22
arnuld wrote:
qsort( arr_of_ptr, ARR_SIZE, sizeof( char* ), p_strcmp );
/* compare 2 strings using pointers */
int p_strcmp( const void* pv1, const void* pv2 )
{
return strcmp( *(char* const*)pv1, *(char* const*)pv2 );
}

int p_strcmp(const void *pv1, const void *pv2)
{
return strcmp(pv1, pv2);
}

--
pete
Jun 27 '08 #23
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 ?

--
http://lispmachine.wordpress.com/
my email ID is at the above address

Jun 27 '08 #24
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.
Jun 27 '08 #25
In article <pa****************************@NoPain.com>,
arnuld <No****@NoPain.comwrote:
>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
Jun 27 '08 #26
arnuld <No****@NoPain.comwrites:
>On Wed, 23 Apr 2008 13:17:26 +0100, Ben Bacarisse wrote:
>>arnuld <Go**********************@gmail.comwrites:
>>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 ?
Yes. Not in the sense of "it won't work" but wrong in the sense of
not right! If I do this:

#define MAX_SIZE 1000
...
char line[MAX_SIZE];
...
if (fgets(line, 902, fp) != NULL) ...

is it wrong? I think so, but the code will compile and execute quite
safely. That is all I was pointing out (see below).
>>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 voidto <pointer to a const pointer to char>
, right ?
Yup. qsort is given an array to sort. All it know about this data is
how big each element is and how many there are:

+----------+----------+----------+----------+----
base-----| element1 | element2 | element3 | element4 | ...
+----------+----------+----------+----------+----

If qsort needs to compare element1 with element4, it passes a pointer
to these elements to the comparison function. These pointers must be
void * because qsort has no type information at all. Your comparison
function gets two pointers like this:

+----------+----------+----------+----------+----
base-----| element1 | element2 | element3 | element4 | ...
+----------+----------+----------+----------+----
^ ^
| |
+---------------+ |
| |
int compare(const void *p1, const void * p2)

In your case, the elements are actually char *s -- they point to
strings like this:

+---+---+---+---+---+ +---+---+---+---+---+
| a | b | c | \n| \0| | d | e | f | \n| \0|
+---+---+---+---+---+ +---+---+---+---+---+
^ ^
| |
+---|------+----------+----------+---|------+----
base-----| element1 | element2 | element3 | element4 | ...
+----------+----------+----------+----------+----
^ ^
| |
+---------------+ |
| |
int compare(const void *p1, const void * p2)

so although p1 is declared void * what it *really* is is a char ** --
it points to a char *. To get at the strings to compare you must
convert p1 to a char ** and access the char * it finds there (by
applying the * operator to the result). We make everything const, but
just blank that out to follow the intent:

int compare(const void *p1, const void * p2)
{
const char *const *cp1 = p1; /* char **cp1 = p1; in effect */
const char *const *cp2 = p2;
return strcmp(*cp1, *cp2);
}

*cp1 is 'element1' -- a char * pointing at "abc\n" and *cp2 is a char
pointing at "def\n". The code in the FAQ does the same (with one less
const) all in a single expression. I prefer to avoid the cast. Does
that help?
>> while( fgets(temp_arr, max, stdin) && num_lines < max )
^^^?

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

incorrect ?
Yes, you pass ARR_SIZE as the max parameter, but temp_arr is of size
STR_SIZE. Now, as it happens, max is smaller than STR_SIZE so this is
safe but fgets shoudl be passed the size of the thing is is to use,
not some other size that relates to something else!
>> 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) ?
Not really. If you write x it is not converted to x * 1 even though
they are the same. If you write malloc(size_arr) you get size_arr
bytes. Multiplying by sizeof(char) is pointless because sizeof(char)
is 1. Some people like to write it out because it reminds them that
are allocating space for chars, but I prefer not to do that.
>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
--
Ben.
Jun 27 '08 #27
arnuld <No****@NoPain.comwrites:
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:
How many elements are you sorting?

--
Ben.
Jun 27 '08 #28
Richard Tobin said:

<snip>
In effect, [sizeof] 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.
s/argument/operand/g

Sorry to be picky, but too few people realise that sizeof is an operator
rather than a function, so I think it's better to be precise in this
situation. (Yes, I know that you know. Just a typo, understood.)

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #29
On Thu, 24 Apr 2008 04:33:14 -0700, Barry Schwarz wrote:
>On Fri, 25 Apr 2008 02:04:45 +0500, arnuld <No****@NoPain.comwrote:
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.

Ohh.. No.. Why on Earth I forgot to use readlines :(
int main( void )
{
const int read_num = readlines( arr_of_ptr, ARR_SIZE );

if( read_num )
{
qsort( arr_of_ptr, read_num, sizeof( char* ), p_strcmp );
printlines( 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?
That was my typo, I think I need a break.

> 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.
fgets() stops reading when it will encounter a '\n' and this is what
reading a line means. So it will retain every newline and in the end will
put '\0'. I think its fine.

I did not get what you mean by "inserts for a line shorter than the
buffer". The last 2 elements of the malloc-ed array will always be '\n'
and '\0', not matter whether the line is small or large, as long it is of
STR_SIZE, I have defined for the limit.

>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.

I just needed to replace the "max" with "STR_SIZE" and it works fine now :)
/* write a program to read a set of lines from input and sort them
* and then print them.
*
* version 2.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 )
{
const int read_num = readlines( arr_of_ptr, STR_SIZE );

if( read_num )
{
qsort( arr_of_ptr, read_num, sizeof( char* ), p_strcmp );
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_ptrwill 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++ );
}
}
/* compare 2 strings using pointers */
int p_strcmp( const void* pv1, const void* pv2 )
{
return strcmp( *(char* const*)pv1, *(char* const*)pv2 );
}

========== OUTPUT =================
/home/arnuld/programs/C $ gcc -ansi -pedantic -Wall -Wextra 5-7.c
/home/arnuld/programs/C $ ./a.out
like
zzz
abc

-------------------------
abc
like
zzz
/home/arnuld/programs/C $

--
http://lispmachine.wordpress.com/
my email ID is at the above address

Jun 27 '08 #30
pete <pf*****@mindspring.comwrites:
arnuld wrote:
> qsort( arr_of_ptr, ARR_SIZE, sizeof( char* ), p_strcmp );
>/* compare 2 strings using pointers */
int p_strcmp( const void* pv1, const void* pv2 )
{
return strcmp( *(char* const*)pv1, *(char* const*)pv2 );
}


int p_strcmp(const void *pv1, const void *pv2)
{
return strcmp(pv1, pv2);
}
Eh? The array being sorted is an array of char *s.

--
Ben.
Jun 27 '08 #31
On Thu, 24 Apr 2008 13:19:53 +0100, Ben Bacarisse wrote:

>arnuld wrote:
we are casting a <pointer to voidto <pointer to a const pointer to
char, right ?

Yup. qsort is given an array to sort. All it know about this data is
how big each element is and how many there are:

so, <char** cpcan be stored in <void* vp>. I thought a ** (pointer to
pointer) needs a ** type to store but here we are storing a ** into a
single *. are they of same size ?

+----------+----------+----------+----------+----
base-----| element1 | element2 | element3 | element4 | ...
+----------+----------+----------+----------+----
....[SNIP]...
int compare(const void *p1, const void * p2) {
const char *const *cp1 = p1; /* char **cp1 = p1; in effect */
const char *const *cp2 = p2;
return strcmp(*cp1, *cp2);
}
}
*cp1 is 'element1' -- a char * pointing at "abc\n" and *cp2 is a char
pointing at "def\n". The code in the FAQ does the same (with one less
const) all in a single expression. I prefer to avoid the cast. Does
that help?

helps in knowing that you think like me on this aspect. I also do not like
casts ;)

thanks for all the effort you put in :)

--
http://lispmachine.wordpress.com/
my email ID is at the above address

Jun 27 '08 #32
Richard Heathfield <rj*@see.sig.invalidwrites:
Richard Tobin said:

<snip>
>In effect, [sizeof] 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.

s/argument/operand/g

Sorry to be picky, but too few people realise that sizeof is an operator
rather than a function, so I think it's better to be precise in this
situation. (Yes, I know that you know. Just a typo, understood.)
That may be being a bit over-picky. The distinction is such a fine
one that the standard gets it wrong. Although the definition of
"argument" states that these are what get passed in function calls,
the text later refers to operators taking arguments.

--
Ben.
Jun 27 '08 #33
On Thu, 24 Apr 2008 12:10:27 +0000, Richard Tobin wrote:

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.

I never expected this to be like this way. I am quite surprised at this
C feature. Are there any other C operators who do not evaluate their
operands ?


--
http://lispmachine.wordpress.com/
my email ID is at the above address

Jun 27 '08 #34
Ben Bacarisse said:
Richard Heathfield <rj*@see.sig.invalidwrites:
>Richard Tobin said:
<snip>
>>>
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.

s/argument/operand/g

Sorry to be picky, but too few people realise that sizeof is an operator
rather than a function, so I think it's better to be precise in this
situation. (Yes, I know that you know. Just a typo, understood.)

That may be being a bit over-picky. The distinction is such a fine
one that the standard gets it wrong.
C89 didn't (I checked). You are right that C99 does. But the fact that the
people who define the language can't get it right doesn't mean that we
have licence to get it wrong.
Although the definition of
"argument" states that these are what get passed in function calls,
the text later refers to operators taking arguments.
There's a potential DR there, for anyone who needs kudos more than they
need lethargy. :-)

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Jun 27 '08 #35
On Fri, 25 Apr 2008 05:17:58 +0500, arnuld <pi***@bingo.comwrote:
>On Thu, 24 Apr 2008 13:19:53 +0100, Ben Bacarisse wrote:

>>arnuld wrote:
we are casting a <pointer to voidto <pointer to a const pointer to
char, right ?

Yup. qsort is given an array to sort. All it know about this data is
how big each element is and how many there are:


so, <char** cpcan be stored in <void* vp>. I thought a ** (pointer to
pointer) needs a ** type to store but here we are storing a ** into a
single *. are they of same size ?
You don't care about the size. A void* is guaranteed convertible to
or from any other type of object pointer. One type of object pointer
is char*. Another is char**. Another is char***. Any of these can
be assigned to a void* and the compiler will generate the appropriate
code to perform the implicit conversion.
Remove del for email
Jun 27 '08 #36
On Fri, 25 Apr 2008 05:02:00 +0500, arnuld <Sp********@gmail.com>
wrote:
>On Thu, 24 Apr 2008 04:33:14 -0700, Barry Schwarz wrote:
snip
>> 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.

fgets() stops reading when it will encounter a '\n' and this is what
reading a line means. So it will retain every newline and in the end will
put '\0'. I think its fine.

I did not get what you mean by "inserts for a line shorter than the
buffer". The last 2 elements of the malloc-ed array will always be '\n'
and '\0', not matter whether the line is small or large, as long it is of
If the amount of data processed by fgets fills your buffer, then fgets
will not have room for the '\n'. In this case the last two characters
will be the (N-1)_th character fgets read followed by a '\0'. There
will be no '\n' in the string.

There is a '\n' in the string returned from fgets only when the amount
of data read leaves at least two unused bytes in the buffer.

snip some more
Remove del for email
Jun 27 '08 #37
On Wed, 23 Apr 2008 08:43:13 +0500, arnuld
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:
You really should get your previous version of the program working
before you fly off on a tangent.
>

/* write a program to read a set of lines from input and sort them
* and then print them.
*
* version 1.0
Surely it should be at least 2.0.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum MAXLINES { ARRSIZE = 100 };

char* arr_of_ptr[ARRSIZE];
char arr_of_lines[ARRSIZE];
You must recognize that there is only room for one line here.

Are you sure that 100 characters is large enough to hold your lines.
>
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 */
How many arguments does qsort require? How many are you providing?
Which one did you forget?

And you still have the wrong number of elements to sort. Why did you
throw the return from readlines away?
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_ptrwill 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++;
It would make commenting on your code a lot easier if you didn't reuse
the object names. arr_of_ptr will be correctly incremented so it
points to the second element in your global pointer array. What will
arr_of_lines be incremented to point to?
++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.


Remove del for email
Jun 27 '08 #38
On Thu, 24 Apr 2008 19:00:29 -0700, Barry Schwarz wrote:

If the amount of data processed by fgets fills your buffer, then fgets
will not have room for the '\n'. In this case the last two characters
will be the (N-1)_th character fgets read followed by a '\0'. There
will be no '\n' in the string.

There is a '\n' in the string returned from fgets only when the amount
of data read leaves at least two unused bytes in the buffer.
yes, this is exactly what I am thinking about. It i snot about newline in
particular it is about the size of the input. Right now, It is fixed to
STR_SIZE limit. Can we make the program to accept any amount of input ?
--
http://lispmachine.wordpress.com/
my email ID is at the above address

Jun 27 '08 #39
Barry Schwarz wrote:
On Fri, 25 Apr 2008 05:02:00 +0500, arnuld <Sp********@gmail.com>
wrote:
>>On Thu, 24 Apr 2008 04:33:14 -0700, Barry Schwarz wrote:

snip
>>> 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.

fgets() stops reading when it will encounter a '\n' and this is what
reading a line means. So it will retain every newline and in the end
will put '\0'. I think its fine.

I did not get what you mean by "inserts for a line shorter than the
buffer". The last 2 elements of the malloc-ed array will always be
'\n' and '\0', not matter whether the line is small or large, as long
it is of

If the amount of data processed by fgets fills your buffer, then fgets
will not have room for the '\n'. In this case the last two characters
will be the (N-1)_th character fgets read followed by a '\0'. There
will be no '\n' in the string.

There is a '\n' in the string returned from fgets only when the amount
of data read leaves at least two unused bytes in the buffer.
This is system specific but at least on some systems you can enter data
two bytes less than the buffer and still dispense with the newline if
you terminate your data by two successive end-of-file sequences. I
think a better way to phrase what you noted above might be to say that
there is a '\n' in the string returned from fgets only if a newline
character is read on or before byte N-1 is read where N is the size of
the buffer supplied to fgets.

Jun 27 '08 #40
arnuld wrote:
>On Thu, 24 Apr 2008 19:00:29 -0700, Barry Schwarz wrote:

>If the amount of data processed by fgets fills your buffer, then
fgets
will not have room for the '\n'. In this case the last two
characters
will be the (N-1)_th character fgets read followed by a '\0'. There
will be no '\n' in the string.

There is a '\n' in the string returned from fgets only when the
amount of data read leaves at least two unused bytes in the buffer.

yes, this is exactly what I am thinking about. It i snot about newline
in particular it is about the size of the input. Right now, It is
fixed to STR_SIZE limit. Can we make the program to accept any amount
of input ?
Yes. If you had been even cursorily following this group you'd have
known that it's a frequently discussed problem and several solutions by
the regulars have been periodically posted. Richard Heathfield
maintains a page on this issue with links to his and other solutions.

<http://www.cpax.org.uk/prg/writings/fgetdata.php>

Jun 27 '08 #41
On Fri, 25 Apr 2008 12:48:55 +0530, santosh <sa*********@gmail.com>
wrote:
>Barry Schwarz wrote:
>On Fri, 25 Apr 2008 05:02:00 +0500, arnuld <Sp********@gmail.com>
wrote:
>>>On Thu, 24 Apr 2008 04:33:14 -0700, Barry Schwarz wrote:

snip
>>>> 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.

fgets() stops reading when it will encounter a '\n' and this is what
reading a line means. So it will retain every newline and in the end
will put '\0'. I think its fine.

I did not get what you mean by "inserts for a line shorter than the
buffer". The last 2 elements of the malloc-ed array will always be
'\n' and '\0', not matter whether the line is small or large, as long
it is of

If the amount of data processed by fgets fills your buffer, then fgets
will not have room for the '\n'. In this case the last two characters
will be the (N-1)_th character fgets read followed by a '\0'. There
will be no '\n' in the string.

There is a '\n' in the string returned from fgets only when the amount
of data read leaves at least two unused bytes in the buffer.

This is system specific but at least on some systems you can enter data
two bytes less than the buffer and still dispense with the newline if
you terminate your data by two successive end-of-file sequences. I
We agree that an end-of-file sequence is a system specific concept.
>think a better way to phrase what you noted above might be to say that
there is a '\n' in the string returned from fgets only if a newline
character is read on or before byte N-1 is read where N is the size of
the buffer supplied to fgets.
My system does not terminate a "line" with a '\n' character in the
file. For files with fixed length records, the line ends after the
specified number of bytes have been processed. For variable length
records, the length of the line is stored in a 16-bit field before the
text of the line and the system processes that many bytes. Therefore,
any behavior dependent on reading a '\n' is specific to the way your
system stores files.

This in no way affects the portable behavior of fgets. If the amount
of data in the "line" leaves at least two unused bytes in the buffer,
fgets MUST terminate the string with a '\n' followed by a '\0'.
Failure to do so violates the required performance specified in the
standard.
Remove del for email
Jun 27 '08 #42
On Sat, 26 Apr 2008 02:42:47 +0500, arnuld <pi***@bingo.comwrote:
>On Thu, 24 Apr 2008 19:00:29 -0700, Barry Schwarz wrote:

>If the amount of data processed by fgets fills your buffer, then fgets
will not have room for the '\n'. In this case the last two characters
will be the (N-1)_th character fgets read followed by a '\0'. There
will be no '\n' in the string.

There is a '\n' in the string returned from fgets only when the amount
of data read leaves at least two unused bytes in the buffer.

yes, this is exactly what I am thinking about. It i snot about newline in
particular it is about the size of the input. Right now, It is fixed to
STR_SIZE limit. Can we make the program to accept any amount of input ?
One common method of dealing with "lines" of unknown length is

call fgets to read sizeof(buffer) characters
if '\n' present in buffer
line is complete
else
do
(process incomplete data as best you can)*
call fgets to read next sizeof(buffer) characters
until '\n' present in buffer

* This is obviously the tricky part. For example:

If the buffer is dynamically allocated, you could use realloc
to enlarge it and read the next set of data into the extended part of
the buffer. When the '\n finally appears, your buffer contains the
complete line.

If your only task is to count character frequency in the file
(a frequent student assignment), you could process the partial line
and then simply reuse the buffer.
Remove del for email
Jun 27 '08 #43
Barry Schwarz <sc******@dqel.comwrites:
<snip>
This in no way affects the portable behavior of fgets. If the amount
of data in the "line" leaves at least two unused bytes in the buffer,
fgets MUST terminate the string with a '\n' followed by a '\0'.
Failure to do so violates the required performance specified in the
standard.
Not by my reading of it. It seems entirely within the allowed
behaviour that the last line (i.e. the one that triggers the
end-of-file condition) might not leave a \n in the buffer. In fact,
both reading a newline and seeing the end of the file are listed as
reasons to stop input and null-terminate the string. Am I missing
something?

--
Ben.
Jun 27 '08 #44
Ben Bacarisse wrote:
pete <pf*****@mindspring.comwrites:
>arnuld wrote:
>> qsort( arr_of_ptr, ARR_SIZE, sizeof( char* ), p_strcmp );
/* compare 2 strings using pointers */
int p_strcmp( const void* pv1, const void* pv2 )
{
return strcmp( *(char* const*)pv1, *(char* const*)pv2 );
}

int p_strcmp(const void *pv1, const void *pv2)
{
return strcmp(pv1, pv2);
}

Eh? The array being sorted is an array of char *s.
Thanks.
I've posted that same kind of error before.
This is what I think the compar function should look like:

int p_strcmp(const void *pv1, const void *pv2)
{
return strcmp(*(const char **)pv1, *(const char **)pv2);
}

--
pete
Jun 27 '08 #45
Ben Bacarisse <be********@bsb.me.ukwrote:
>
That may be being a bit over-picky. The distinction is such a fine
one that the standard gets it wrong. Although the definition of
"argument" states that these are what get passed in function calls,
the text later refers to operators taking arguments.
Only in one place. I've made a note to fix it.

-Larry Jones

In short, open revolt and exile is the only hope for change? -- Calvin
Jun 27 '08 #46
On Fri, 25 Apr 2008 14:26:35 +0100, Ben Bacarisse
<be********@bsb.me.ukwrote:
>Barry Schwarz <sc******@dqel.comwrites:
<snip>
>This in no way affects the portable behavior of fgets. If the amount
of data in the "line" leaves at least two unused bytes in the buffer,
fgets MUST terminate the string with a '\n' followed by a '\0'.
Failure to do so violates the required performance specified in the
standard.

Not by my reading of it. It seems entirely within the allowed
behaviour that the last line (i.e. the one that triggers the
end-of-file condition) might not leave a \n in the buffer. In fact,
both reading a newline and seeing the end of the file are listed as
reasons to stop input and null-terminate the string. Am I missing
something?
I think we are using the term buffer in two different senses. I used
buffer to mean the "array" pointed to by the first argument to fgets.
You appear to be using it to refer to the I/O buffer used to manage
the stream. In that case I agree with you. I make no claim as to the
contents of the stream buffer. What I do claim is that santosh's
assertion that two end of file sequences (whatever that is) can
prevent fgets from storing a '\n' in the array buffer would a
violation of the standard. Ignoring error conditions, if the number
of bytes read is at least two less than the second argument to fgets,
then fgets must store both '\n' and '\0' in sequence immediately
following the last byte read. Failure to do so is a violation of its
behavior mandate. The only time the '\n' is not stored is when the
number of bytes read is exactly one less than the quantity specified
in the second argument.
Remove del for email
Jun 27 '08 #47
In article <pa****************************@bingo.com>
arnuld <pi***@bingo.comwrote:
>so, <char** cpcan be stored in <void* vp>.
Yes.
>I thought a ** (pointer to pointer) needs a ** type to store
Ideally, given a value of some type T, the best place to store
it is an object declared with that type. Given:

typedef /* insert some data type here */ T;
/*
eg,
typedef double T;
or typedef short T;
or typedef char **T;
or typedef struct foo *T;
or even
typedef void (*T)(void);
*/

you would then do:

T var;
...
var = value;

to store the value of type T in a variable of type T.

Sometimes, however, we have -- for whatever reason -- a variable
(or other object, if "variable" refers only to named objects)
with the "wrong" type. For instance:

double var;
...
var = some_integer_valued_function();

What is required is that the object into which we save this value
be "sufficiently capacious" to store any possible value. So
this question:
>but here we are storing a ** into a single *. are they of same size ?
is not quite aimed correctly. If they were the same size, that
might be good enough, because at least the "place we are saving
the value" has enough *bits* to store the value. But "same size"
is not really good enough -- an int and a float are often the
same size:

#include <stdio.h>
int main(void) {
printf("%d %d\n", (int)sizeof(int), (int)sizeof(float));
return 0;
}

This will print "4 4" on many machines (I have one here that does
.... well, actually, I have quite a few, but will use just one of
them). But we cannot store just any float in an int, nor vice
versa:

#include <stdio.h>
#include <limits.h>
int main(void) {
float f;
int i;

f = 2109876543;
i = 3.5;
printf("%d (should be %d); %f (should be %f)\n",
(int)f, 2109876541, (double)i, 3.5);
return 0;
}

On my machine, I get:

% ./t
2109876480 (should be 2109876541); 3.000000 (should be 3.500000)

So we see that on my machine, even though int and float are the
same size, they cannot store all the same values. The "int" variable
loses the fraction, while the "float" variable sometimes loses the
last few digits of any "too-big" integer (certain powers of two
are saved correctly, but other values are rounded to the nearest
power of two).

If we were to store "int"s in "double"s, though, at least on this
particular machine, all "int" values would fit without rounding
problems. So a "double" suffices to store any "int" value: it has
enough bits *and* it never "corrupts" any of the original bits.
Even though assigning INT_MAX to a "double" changes the set of bits
stored (see <http://web.torek.net/torek/c/numbers.htmlfor a
discussion of representations), we can later convert the double
back to an int, and we always get the original number back.

What happened back in the 1980s was that the ANSI C committee --
the people involved in X3J11 -- were at some meeting(s), and had
some discussion(s), in which various members said they wanted to
come up with a new data type. This new type should be "big enough"
to store any valid data-pointer type.

On most machines, all data pointer types are the same, but on a
few -- especially back then -- there were some that had more than
one "kind" of pointer, having the bits moved around (byte vs word
pointers) on some machines, or even different sizes of pointers on
others. But even on these "oddball" machines, there was always
some way to store the "worst case" pointers. Even if the compiler
might have to have a special struct or union type internally, there
would be *some* way to gather up all the information from any
"specific" pointer type -- a "T *" for some data-type T -- into a
"generic" form.

What the X3J11 (ANSI C) committee folks needed to do, then, was
require implementations to provide a "generic data pointer" type,
along with pairs of chunks of implementation-specific code. One
chunk of each pair would take a *specific* pointer value, gather
up everything about it, and store it into this "generic pointer".
The other chunk would take one of these "generic pointers", having
been constructed earlier from some specific pointer, and convert
it back to the appropriate specfiic pointer.

For discussion, let us call the generic pointer type "genptr_t",
for the moment. The ANSI folks might even have considered using
a name like this (I was not at the meetings, I only read some
of the eventual paperwork, so I do not know if they did).

On machines with multiple "flavors" of pointers, these "chunks
of code" (as I am calling them here) were usually one pair of
instructions. For instance, a machine with both byte and word
pointers will usually be able to point to any individual byte
with a byte pointer, so it can use "byte pointer" for genptr_t.
Then, given a value of type "T *", the value itself is either
already a byte pointer, or is a word pointer. So:

T *orig;
genptr_t save_it;
... something that sets "orig" ...
save_it = (genptr_t)orig;

needs to use "convert word pointer to byte pointer" if "T *" is
a word pointer. If "T *" is already a byte pointer, it just
uses an ordinary "copy" instruction (often spelled "move", but
it copies, rather than emptying out the original :-) ).

To restore the original value:

... code that modifies "orig" ...
orig = (T *)save_it;

we just need to reverse the process, either with another copy, or
with a "convert byte pointer to word pointer" instruction. Note
that the compiler did (and does) not have to know whether "save_it"
originally came from a byte or word pointer. You, the C programmer,
tell the compiler which kind to change it *to*. (In this particular
case, you supply the type with a cast.) It is *your* responsibility
to make sure that whatever value is in save_it "came from" a value
of the right type.

On machines with only one "flavor" of pointer, like the x86 for
instance, any pointer is already suitable for a genptr_t, so we
only need to use the machine's "copy value" ("mov") instruction.
So this makes writing a C compiler for these machines even
easier. All the "genptr_t" does is leave room for the oddball
machines: it costs nothing on the x86.

The weirdest part of this whole story, though, is the spelling that
the X3J11 committee folks came up with for "genptr_t". Instead of
having some <stdwhatever.hfile provide it, or having the compiler
pre-load it using that name, they decided to have the compiler
pre-load it, but using the spelling "void *".

So "void *" is really a genptr_t -- a generic pointer. This is
a very special pointer, in two ways:

- it is always big enough to hold *any* data pointer (not
necessarily a function pointer, though), and

- you can convert "void *" to and from "T *", where T is any
data type, without using a cast. (Other pointer conversions
require using casts.)

That second property is probably what convinced the committee
to spell the type "void *", making it built-in to the compilers.

Note, by the way, that "void *" is itself a data type, so one
can point to a "void *", giving a "void **". This is just a
regular old (non-generic) pointer type, though: it points
specifically to a "void *", never to any other type.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html
Jun 27 '08 #48
Barry Schwarz <sc******@dqel.comwrites:
On Fri, 25 Apr 2008 14:26:35 +0100, Ben Bacarisse
<be********@bsb.me.ukwrote:
>>Barry Schwarz <sc******@dqel.comwrites:
<snip>
>>This in no way affects the portable behavior of fgets. If the amount
of data in the "line" leaves at least two unused bytes in the buffer,
fgets MUST terminate the string with a '\n' followed by a '\0'.
Failure to do so violates the required performance specified in the
standard.

Not by my reading of it. It seems entirely within the allowed
behaviour that the last line (i.e. the one that triggers the
end-of-file condition) might not leave a \n in the buffer. In fact,
both reading a newline and seeing the end of the file are listed as
reasons to stop input and null-terminate the string. Am I missing
something?

I think we are using the term buffer in two different senses. I used
buffer to mean the "array" pointed to by the first argument to fgets.
You appear to be using it to refer to the I/O buffer used to manage
the stream. In that case I agree with you. I make no claim as to the
contents of the stream buffer.
No, I am talking about the same buffer as you. I, too, make no claims
about any intermediate stream buffers.
What I do claim is that santosh's
assertion that two end of file sequences (whatever that is)
[It is just how some systems let you signal an end-of-file when the
preceding input is not a newline. Thus, on Linux, to give a program a
three-byte input stream consisting of 'a', 'b' and 'c' you would type
"abc^D^D" at it.]
can
prevent fgets from storing a '\n' in the array buffer would a
violation of the standard. Ignoring error conditions, if the number
of bytes read is at least two less than the second argument to fgets,
then fgets must store both '\n' and '\0' in sequence immediately
following the last byte read. Failure to do so is a violation of its
behavior mandate.
All I can say is that is not how I read that part of the standard.
The governing text seems to be section 7.19.7.2 para. 2:

"The fgets function reads at most one less than the number of
characters specified by n from the stream pointed to by stream into
the array pointed to by s. No additional characters are read after a
new-line character (which is retained) or after end-of-file. A null
character is written immediately after the last character read into
the array."

which I can't read as mandating a newline being added to the buffer
unless one was there in the first place. The only place where there
may not be one is of course, by definition, the last line.

If you are right, and there are further restrictions that mandate a
newline character (space permitting) in the last successful return
from fgets, then gcc's fgets is not conforming (as are several other C
libraries I have used before but no longer have access to).

Of course, it is permissible for an implementation to require that the
last line of all text streams include a newline. So the behaviour you
say is required by the standard may be imposed by an implementation;
but this is "optional" and, in any case, would only apply to text
streams.

--
Ben.
Jun 27 '08 #49
arnuld wrote:
>On Thu, 24 Apr 2008 12:10:27 +0000, Richard Tobin wrote:

>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.


I never expected this to be like this way. I am quite surprised at this
C feature. Are there any other C operators who do not evaluate their
operands ?
& address operator

--
pete
Jun 27 '08 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: aredo3604gif | last post by:
On Sun, 10 Apr 2005 19:46:32 GMT, aredo3604gif@yahoo.com wrote: >The user can dynamically enter and change the rule connection between >objects. The rule is a "<" and so given two objects: >a <...
7
by: Foodbank | last post by:
Hi everyone. I'm having trouble with this radix sorting program. I've gotten some of it coded except for the actual sorting :( The book I'm teaching myself with (Data Structures Using C and...
8
by: ianaré | last post by:
Hey all, if i use a os.walk() to append files to a list like so... files = root = self.path.GetValue() # wx.TextCtrl input filter = self.fileType.GetValue().lower() # wx.TextCtrl input...
0
by: sweta kandula | last post by:
hello this is sweta and under grad from india i have some doubt regarding my programming i shall explain you the project in detaillll my project is concerned with DFS and Topological sorting...
2
by: RajasScripts | last post by:
Hi I need some guidance in sorting HTML input tag sorting.I am able to sort columns with out input tag and with dates.But the only problem is I am not able to sort a column which is text box with...
11
by: Trent | last post by:
Running this I see that on first run, both bubble and selection sort have 9 sort counts while insertion sort has ZERO. With a sorted list, should this be ZERO for all? Also bsort and Ssort have...
7
by: abracadabra | last post by:
I am reading an old book - Programming Pearls 2nd edition recently. It says, "Even though the general C++ program uses 50 times the memory and CPU time of the specialized C program, it requires...
1
by: Ahmed Yasser | last post by:
Hi all, i have a problem with the datagridview sorting, the problem is a bit complicated so i hope i can describe in the following steps: 1. i have a datagridview with two columns...
3
KevinADC
by: KevinADC | last post by:
If you are entirely unfamiliar with using Perl to sort data, read the "Sorting Data with Perl - Part One and Two" articles before reading this article. Beginning Perl coders may find this article...
5
by: lemlimlee | last post by:
hello, this is the task i need to do: For this task, you are to develop a Java program that allows a user to search or sort an array of numbers using an algorithm that the user chooses. The...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.