468,727 Members | 1,667 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,727 developers. It's quick & easy.

K&R2 , exercise 7.6

PURPOSE :: see statement in comments

GOT: Segmentation Fault

I guess the segfault is sourced in the compile-time warning but I am
giving a char* to the function already.


/* K&R2, section 7.7, exercise 7.6
*
* write a program to compare 2 files, printing that first line
* where they differ.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum MAXSIZE { ARRSIZE=1000 };

void compare_files( FILE*, FILE* );
void print_line( char* );
int main( int argc, char* argv[] )
{
FILE *pf1, *pf2;

if( argc !=3 )
{
fprintf( stderr, "You iDiOT, I expect 2 files as input. \n" );
exit(EXIT_FAILURE);
}
/* open files */
pf1 = fopen( *++argv, "r" );
pf2 = fopen( *++argv, "r" );

/* error check */
if( pf1 == NULL || pf2 == NULL )
{
fprintf( stderr, "error opening files\n");
exit(EXIT_FAILURE);
}
else
{
compare_files( pf1,pf2 );
}

/* don't forget to close the files */
fclose( pf1 );
fclose( pf2 );
return 0;
}

/* compare 2 files */
void compare_files( FILE* pf1, FILE* pf2 )
{
int c1, c2, match;
char *line1, *line2;
char *begin_line1, *begin_line2;

match = 1;

while( ((line1 = fgets( line1, ARRSIZE, pf1 )) != NULL) ||
((line2 = fgets( line2, ARRSIZE, pf2 )) != NULL))
{
begin_line1 = line1;
begin_line2 = line2;

for( c1 = *line1, c2 = *line2; c1 != '\0' && c2 != '\0'; ++line1,
++line2 )
{
if ( c1 != c2 )
{
match = 0;
print_line( begin_line1 );
printf("\n-----------------------\n"); print_line( begin_line2 );
}
}
}
}

void print_line( char* line )
{
printf("%s\n", *line++);
}

================== OUTPUT ======================
[arnuld@raj C]$ gcc -ansi -pedantic -Wall -Wextra 7-6.c
7-6.c: In function `print_line':
7-6.c:88: warning: format argument is not a pointer (arg 2)

[arnuld@raj C]$ ./a.out
You iDiOT, I expect 2 files as input.

[arnuld@raj C]$ ./a.out 7-6.c 5-4.c
Segmentation fault
--
http://lispmachine.wordpress.com/
my email ID is at the above address

Jun 27 '08 #1
82 2347
arnuld said:
PURPOSE :: see statement in comments

GOT: Segmentation Fault
<snip>
int c1, c2, match;
char *line1, *line2;
Where do these point? (Hint: nowhere in particular.)
char *begin_line1, *begin_line2;

match = 1;

while( ((line1 = fgets( line1, ARRSIZE, pf1 )) != NULL) ||
((line2 = fgets( line2, ARRSIZE, pf2 )) != NULL))
They certainly don't point to ARRSIZE bytes of memory that you have the
right to update.

<snip>
void print_line( char* line )
{
printf("%s\n", *line++);
void print_line(const char *line)
{
puts(line);
}

--
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 #2
On Mon, 21 Apr 2008 10:02:16 +0000, Richard Heathfield wrote:
arnuld said:
Where do these point? (Hint: nowhere in particular.)

OK, here is the 2nd version:
/* K&R2, section 7.7, exercise 7.6
*
* write a program to compare 2 files, printing that first line
* where they differ.
*
* version 1.1
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum MAXSIZE { ARRSIZE=1000 };

void compare_files( FILE*, FILE* );
void print_line( const char* );
int main( int argc, char* argv[] )
{
FILE *pf1, *pf2;

if( argc !=3 )
{
fprintf( stderr, "You iDiOT, I expect 2 files as input. \n" );
exit(EXIT_FAILURE);
}
/* open files */
pf1 = fopen( *++argv, "r" );
pf2 = fopen( *++argv, "r" );

/* error check */
if( pf1 == NULL || pf2 == NULL )
{
fprintf( stderr, "error opening files\n");
exit(EXIT_FAILURE);
}
else
{
compare_files( pf1,pf2 );
}

/* don't forget to close the files */
fclose( pf1 );
fclose( pf2 );
return 0;
}

/* compare 2 files */
void compare_files( FILE* pf1, FILE* pf2 )
{
int match;
char c1, c2;
char line1[ARRSIZE];
char line2[ARRSIZE];
char *begin_line1, *begin_line2, *p1, *p2;
match = 1;

while( (fgets( line1, ARRSIZE, pf1 ) != NULL) ||
(fgets( line2, ARRSIZE, pf2 ) != NULL))
{
begin_line1 = line1;
begin_line2 = line2;

p1 = line1;
p2 = line2;
for( c1 = *p1, c2 = *p2; c1 != '\0' && c2 != '\0'; ++p1, ++p2 )
{
if ( c1 != c2 )
{
match = 0;
print_line( begin_line1 );
printf("\n-----------------------\n"); print_line( begin_line2 );
}
}
}
}

void print_line( const char* line )
{
while( *line != '\0')
{
puts(*line++);
}
}

================ OUTPUT =======================

[arnuld@raj C]$ gcc -ansi -pedantic -Wall -Wextra 7-6.c
7-6.c: In function `print_line':
7-6.c:96: warning: passing arg 1 of `puts' makes pointer from integer
without a cast
[arnuld@raj C]$ ./a.out 7-6.c replace-blanks.c Segmentationfault
[arnuld@raj C]$



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

Jun 27 '08 #3
arnuld wrote:
void print_line( const char* line )
{
while( *line != '\0')
{
puts(*line++);
}
}

================ OUTPUT =======================

[arnuld@raj C]$ gcc -ansi -pedantic -Wall -Wextra 7-6.c
7-6.c: In function `print_line':
7-6.c:96: warning: passing arg 1 of `puts' makes pointer from integer
without a cast
[arnuld@raj C]$ ./a.out 7-6.c replace-blanks.c Segmentationfault
[arnuld@raj C]$
Ask yourself: what does `puts` accept as an parameter? What is
the type of the expression `*line++`? Are C characters a kind
of integer? Do you really expect an integer to be freely and
automatically converted to an integer?

--
"It took a very long time, much longer than the most /Sector General/
generous estimates."

Hewlett-Packard Limited Cain Road, Bracknell, registered no:
registered office: Berks RG12 1HN 690597 England

Jun 27 '08 #4
arnuld wrote:
>On Mon, 21 Apr 2008 10:02:16 +0000, Richard Heathfield wrote:
>arnuld said:
>Where do these point? (Hint: nowhere in particular.)


OK, here is the 2nd version:
/* K&R2, section 7.7, exercise 7.6
*
* write a program to compare 2 files, printing that first line
* where they differ.
*
* version 1.1
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum MAXSIZE { ARRSIZE=1000 };

void compare_files( FILE*, FILE* );
void print_line( const char* );
int main( int argc, char* argv[] )
{
FILE *pf1, *pf2;

if( argc !=3 )
{
fprintf( stderr, "You iDiOT, I expect 2 files as input. \n" );
exit(EXIT_FAILURE);
}
/* open files */
pf1 = fopen( *++argv, "r" );
pf2 = fopen( *++argv, "r" );

/* error check */
if( pf1 == NULL || pf2 == NULL )
{
fprintf( stderr, "error opening files\n");
exit(EXIT_FAILURE);
}
else
{
compare_files( pf1,pf2 );
}

/* don't forget to close the files */
fclose( pf1 );
fclose( pf2 );
return 0;
}

/* compare 2 files */
void compare_files( FILE* pf1, FILE* pf2 )
{
int match;
char c1, c2;
char line1[ARRSIZE];
char line2[ARRSIZE];
char *begin_line1, *begin_line2, *p1, *p2;
match = 1;

while( (fgets( line1, ARRSIZE, pf1 ) != NULL) ||
(fgets( line2, ARRSIZE, pf2 ) != NULL))
{
begin_line1 = line1;
begin_line2 = line2;

p1 = line1;
p2 = line2;
for( c1 = *p1, c2 = *p2; c1 != '\0' && c2 != '\0'; ++p1, ++p2 )
{
if ( c1 != c2 )
{
match = 0;
print_line( begin_line1 );
printf("\n-----------------------\n"); print_line( begin_line2
); }
}
}
}

void print_line( const char* line )
{
while( *line != '\0')
{
puts(*line++);
}
}

================ OUTPUT =======================

[arnuld@raj C]$ gcc -ansi -pedantic -Wall -Wextra 7-6.c
7-6.c: In function `print_line':
7-6.c:96: warning: passing arg 1 of `puts' makes pointer from integer
without a cast
What does that warning tell you?
[arnuld@raj C]$ ./a.out 7-6.c replace-blanks.c Segmentationfault
[arnuld@raj C]$
You lied to your compiler (and he spotted it and warned you about it) and he
got his revenge...

Bye, Jojo
Jun 27 '08 #5
On Mon, 21 Apr 2008 11:35:00 +0100, Chris Dollin wrote:

Ask yourself: what does `puts` accept as an parameter? What is
the type of the expression `*line++`?

K&R2 Appendix B, page 247:

"int puts( const char *s )

puts writes the string s and the newline to stdout. It returns EOF
if an error occurs, non-negative otherwise"
Now there are no strings in C. We have arrays of characters. It is same
like printf() which accepts %s as an array of chars. So <lineis a single
line of input form file stored into an array of chars.

Are C characters a kind
of integer? Do you really expect an integer to be freely and
automatically converted to an integer?
that was my mistake, my typo(s), I think I am getting sleepy. I just
recently shifted from North-India to South-India and I had to change my
food-habits. I am not able to get any food I used to eat from last 27
years (since I was born). So I have lots of difficulties in living a
normal daily routine here.


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

Jun 27 '08 #6
arnuld said:
>On Mon, 21 Apr 2008 11:35:00 +0100, Chris Dollin wrote:

>Ask yourself: what does `puts` accept as an parameter? What is
the type of the expression `*line++`?


K&R2 Appendix B, page 247:

"int puts( const char *s )

puts writes the string s and the newline to stdout. It returns
EOF
if an error occurs, non-negative otherwise"
I don't know whether you noticed, but I gave you a working version of
print_line - and you appear to have broken it again.
>

Now there are no strings in C.
Wrong. In C, a string is a contiguous sequence of characters, terminated by
the first null character.
We have arrays of characters. It is same
like printf() which accepts %s as an array of chars.
Wrong. printf interprets %s as meaning "the parameter matching this format
specifier is a ##pointer## to the first character in a contiguous sequence
of characters that is terminated by a null character" - in other words, %s
means "I'm giving you a string".

<snip>

--
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 #7
On Mon, 21 Apr 2008 11:57:59 +0000, Richard Heathfield wrote:

I don't know whether you noticed, but I gave you a working version of
print_line - and you appear to have broken it again.

yes. I fixed it again but I am using putchar() now.
Wrong. In C, a string is a contiguous sequence of characters, terminated
by the first null character.
but these 2 are different:

char arr[] = "Richard";
char* pc = "Richard";

both are contiguous sequence of characters ended by '\0'.

Wrong. printf interprets %s as meaning "the parameter matching this
format specifier is a ##pointer## to the first character in a contiguous
sequence of characters that is terminated by a null character" - in
other words, %s means "I'm giving you a string".

you can never use the pc for %s in printf(). Thats what I meant, there
are no strings, only arrays of chars. I tried to print the pc but all I
got was:
^A^M^D @#

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

Jun 27 '08 #8
On Mon, 21 Apr 2008 10:02:16 +0000, Richard Heathfield wrote:
>arnuld wrote:
int c1, c2, match;
char *line1, *line2;
Where do these point? (Hint: nowhere in particular.)

okay, here is the 3rd version of the program. It compiles and runs, the
only thing is semantic-bug, it always does one thing, no matter whether 2
files are same or different:

/* K&R2, section 7.7, exercise 7.6
*
* write a program to compare 2 files, printing that first line
* where they differ.
*
* version 1.2
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum MAXSIZE { ARRSIZE=1000 };

void compare_files( FILE*, FILE* );
void print_line( const char* );
int main( int argc, char* argv[] )
{
FILE *pf1, *pf2;

if( argc !=3 )
{
fprintf( stderr, "You iDiOT, I expect 2 files as input. \n" );
exit(EXIT_FAILURE);
}
/* open files */
pf1 = fopen( *++argv, "r" );
pf2 = fopen( *++argv, "r" );

/* error check */
if( pf1 == NULL || pf2 == NULL )
{
fprintf( stderr, "error opening files\n");
exit(EXIT_FAILURE);
}
else
{
compare_files( pf1,pf2 );
}

/* don't forget to close the files */
fclose( pf1 );
fclose( pf2 );
return 0;
}

/* compare 2 files */
void compare_files( FILE* pf1, FILE* pf2 )
{
int match;
char c1, c2;
char line1[ARRSIZE];
char line2[ARRSIZE];
const char *begin_line1, *begin_line2, *p1, *p2;
match = 1;

while( (fgets( line1, ARRSIZE, pf1 ) != NULL) || (fgets( line2, ARRSIZE, pf2 ) != NULL))
{
begin_line1 = line1;
begin_line2 = line2;

p1 = line1;
p2 = line2;
for( c1 = *p1, c2 = *p2; c1 != '\0' && c2 != '\0'; ++p1, ++p2 )
{
if ( c1 != c2 )
{
match = 0;
print_line( begin_line1 );
printf("\n-----------------------\n");
print_line( begin_line2 );
return;
}
}
}
}

void print_line( const char* line )
{
while( *line != '\0')
{
putchar(*line++);
}
}

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

Jun 27 '08 #9
In article <pa****************************@NoPain.Rome>,
arnuld <No****@NoPain.Romewrote:
>Wrong. In C, a string is a contiguous sequence of characters, terminated
by the first null character.
>but these 2 are different:

char arr[] = "Richard";
char* pc = "Richard";

both are contiguous sequence of characters ended by '\0'.
And they are both strings.
>Wrong. printf interprets %s as meaning "the parameter matching this
format specifier is a ##pointer## to the first character in a contiguous
sequence of characters that is terminated by a null character" - in
other words, %s means "I'm giving you a string".
>you can never use the pc for %s in printf().
What do you mean by "the pc"? Do you mean the variable pc declared
above? If so, you can certainly print it with %s.

-- Richard
--
:wq
Jun 27 '08 #10
arnuld wrote:
>On Mon, 21 Apr 2008 11:57:59 +0000, Richard Heathfield wrote:
>Wrong. In C, a string is a contiguous sequence of characters,
terminated by the first null character.

but these 2 are different:

char arr[] = "Richard";
char* pc = "Richard";

both are contiguous sequence of characters ended by '\0'.
pc is a pointer to a (read-only) string
arr is an array containing a (modifyable) string
>Wrong. printf interprets %s as meaning "the parameter matching this
format specifier is a ##pointer## to the first character in a
contiguous sequence of characters that is terminated by a null
character" - in other words, %s means "I'm giving you a string".


you can never use the pc for %s in printf().
Nonsense. In both cases printf only sees a pointer to char and prints that
up to the terminating \0.
Thats what I meant, there
are no strings, only arrays of chars. I tried to print the pc but all
I got was:
^A^M^D @#
They you must have done something severly wrong.

Bye, Jojo
Jun 27 '08 #11
arnuld <No****@NoPain.Romewrites:
okay, here is the 3rd version of the program. It compiles and runs, the
only thing is semantic-bug, it always does one thing, no matter whether 2
files are same or different:
<snip>
/* compare 2 files */
void compare_files( FILE* pf1, FILE* pf2 )
{
int match;
char c1, c2;
char line1[ARRSIZE];
char line2[ARRSIZE];
const char *begin_line1, *begin_line2, *p1, *p2;
match = 1;
What is this for?
while( (fgets( line1, ARRSIZE, pf1 ) != NULL) || (fgets( line2,
ARRSIZE, pf2 ) != NULL))
The logic here is wrong. || is a "a short-circuit" operator. Once
the first half gets a line the second half will not be executed. You
must read pairs of lines and I'd stop when one of the files runs out.
{
begin_line1 = line1;
begin_line2 = line2;

p1 = line1;
p2 = line2;
for( c1 = *p1, c2 = *p2; c1 != '\0' && c2 != '\0'; ++p1, ++p2 )
{
if ( c1 != c2 )
Why so many variables? What is wrong with strcmp?
{
match = 0;
print_line( begin_line1 );
printf("\n-----------------------\n");
print_line( begin_line2 );
return;
}
}
}
}

void print_line( const char* line )
{
while( *line != '\0')
{
putchar(*line++);
}
}
What is the point of this function? It is just fputs, in effect.

--
Ben.
Jun 27 '08 #12
On Mon, 21 Apr 2008 13:56:44 +0100, Ben Bacarisse wrote:
>arnuld wrote:
What is this for?
:-\
> while( (fgets( line1, ARRSIZE, pf1 ) != NULL) || (fgets( line2,
ARRSIZE, pf2 ) != NULL))
The logic here is wrong. || is a "a short-circuit" operator. Once
the first half gets a line the second half will not be executed. You
must read pairs of lines and I'd stop when one of the files runs out.
As per my slowly developing C knowledge :P, If one line ends before ther
other then of course, the lines are not equal. This is true when either
both or any one of them runs out.

may be I did not understand your logic here but right now this is the
limit of my thinking.

What is the point of this function? It is just fputs, in effect.

K&R2 never talked about using it. So I never came across it.

Here is the 4th revision of the program. As usual output is not what I
wanted :(

/* K&R2, section 7.7, exercise 7.6
*
* write a program to compare 2 files, printing that first line
* where they differ.
*
* version 1.3
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum MAXSIZE { ARRSIZE=1000 };

void compare_files( FILE*, FILE* );
int main( int argc, char* argv[] )
{
FILE *pf1, *pf2;

if( argc !=3 )
{
fprintf( stderr, "You iDiOT, I expect 2 files as input. \n" );
exit(EXIT_FAILURE);
}
/* open files */
pf1 = fopen( *++argv, "r" );
pf2 = fopen( *++argv, "r" );

/* error check */
if( pf1 == NULL || pf2 == NULL )
{
fprintf( stderr, "error opening files\n");
exit(EXIT_FAILURE);
}
else
{
compare_files( pf1,pf2 );
}

/* don't forget to close the files */
fclose( pf1 );
fclose( pf2 );
return 0;
}

/* compare 2 files */
void compare_files( FILE* pf1, FILE* pf2 )
{
char line1[ARRSIZE];
char line2[ARRSIZE];
const char *begin_line1, *begin_line2, *p1, *p2;
while( (fgets( line1, ARRSIZE, pf1 ) != NULL) ||
(fgets( line2, ARRSIZE, pf2 ) != NULL))
{
begin_line1 = p1 = line1;
begin_line2 = p2 = line2;

if( !strcmp( p1, p2 ) )
{
puts( begin_line1 );
printf("-------------- Lines differ here ---------------\n");
puts( begin_line2 );
return;
}
}
}
============= OUTPUT =================

[arnuld@raj C]$ gcc -ansi -pedantic -Wall -Wextra test.c
[arnuld@raj C]$ ./a.out file1.txt file2.txt


-------------- Lines differ here ---------------


[arnuld@raj C]$





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

Jun 27 '08 #13
arnuld wrote:
>On Mon, 21 Apr 2008 11:35:00 +0100, Chris Dollin wrote:

>Ask yourself: what does `puts` accept as an parameter? What is
the type of the expression `*line++`?


K&R2 Appendix B, page 247:

"int puts( const char *s )

puts writes the string s and the newline to stdout. It returns EOF
if an error occurs, non-negative otherwise"

Now there are no strings in C.
What makes you think that?
We have arrays of characters. It is same
like printf() which accepts %s as an array of chars. So <lineis a single
line of input form file stored into an array of chars.
`line` needn't have come from any of the program's input files:

puts( "I do not come from from this program's input files." );

--
"Thereafter, events may roll unheeded." /Foundation/

Hewlett-Packard Limited Cain Road, Bracknell, registered no:
registered office: Berks RG12 1HN 690597 England

Jun 27 '08 #14
arnuld schreef:
>On Mon, 21 Apr 2008 13:56:44 +0100, Ben Bacarisse wrote:
>>arnuld wrote:


>> while( (fgets( line1, ARRSIZE, pf1 ) != NULL) || (fgets( line2,
ARRSIZE, pf2 ) != NULL))
>The logic here is wrong. || is a "a short-circuit" operator. Once
the first half gets a line the second half will not be executed. You
must read pairs of lines and I'd stop when one of the files runs out.
[snip]
>
while( (fgets( line1, ARRSIZE, pf1 ) != NULL) ||
(fgets( line2, ARRSIZE, pf2 ) != NULL))
You are still not seeing it ?
If you read line1 with success you will NOT read line2.

|| means OR, so short circuit will prevent you from evaluating the second part (after the || ) if the first is true
because the answer is already known.

You could try && instead and see if that fixes it.
Good luck,
Edwin
Jun 27 '08 #15
arnuld <No****@NoPain.Romewrites:
>On Mon, 21 Apr 2008 13:56:44 +0100, Ben Bacarisse wrote:
>> while( (fgets( line1, ARRSIZE, pf1 ) != NULL) || (fgets( line2,
ARRSIZE, pf2 ) != NULL))
>The logic here is wrong. || is a "a short-circuit" operator. Once
the first half gets a line the second half will not be executed. You
must read pairs of lines and I'd stop when one of the files runs out.

As per my slowly developing C knowledge :P, If one line ends before ther
other then of course, the lines are not equal. This is true when either
both or any one of them runs out.

may be I did not understand your logic here but right now this is the
limit of my thinking.
<snip>
Here is the 4th revision of the program. As usual output is not what I
wanted :(
<snip>
while( (fgets( line1, ARRSIZE, pf1 ) != NULL) ||
(fgets( line2, ARRSIZE, pf2 ) != NULL))
{
This does not do what you think it does. In C, the following is
perfectly correct:

if (x == 0 || y/x 1)

y/x will never be evaluated when x == 0 because the second part of the
'||' is not evaluated when the first part is found to be true
(non-zero). In your case, the second file is never read until first
file read *fails*. This is, absolutely, not what you wanted to
happen.

--
Ben.
Jun 27 '08 #16
arnuld wrote:
>On Mon, 21 Apr 2008 11:57:59 +0000, Richard Heathfield wrote:
>I don't know whether you noticed, but I gave you a working version of
print_line - and you appear to have broken it again.

yes. I fixed it again but I am using putchar() now.
>Wrong. In C, a string is a contiguous sequence of characters,
terminated by the first null character.

but these 2 are different:

char arr[] = "Richard";
char* pc = "Richard";
Yes. The first declaration creates an array (named arr) of the length
needed to store the string literal "Richard" which is of eight
characters including the terminating newline. Note that the elements of
arr are subsequently modifiable, as you have not const qualified it.
It's identical to any other char array, merely initialised in a
slightly special manner.

The second declaration says that pc is a pointer to type char and
initialises it to the address of the start of the string "Richard",
which is placed somewhere in memory according to the compiler's
convinience. The main difference with the first declaration is that
here pc is simply a char * and points to a string literal which cannot
be modified without invoking undefined behaviour. However pc can always
be set to point elsewhere in which case you'll lose access to the
string literal "Richard" unless you preserve it's address elsewhere.
both are contiguous sequence of characters ended by '\0'.
The first is a char array into which a string has been _copied_ . The
latter is a char * which points to a string literal somewhere in
memory.

I hope the difference is clear...
>Wrong. printf interprets %s as meaning "the parameter matching this
format specifier is a ##pointer## to the first character in a
contiguous sequence of characters that is terminated by a null
character" - in other words, %s means "I'm giving you a string".


you can never use the pc for %s in printf(). Thats what I meant, there
are no strings, only arrays of chars. I tried to print the pc but all
I got was:
^A^M^D @#
You can perfectly print both the declarations you have given above using
the %s printf specifier. The %s format specifier looks for a char *
argument and prints all characters upto the first null character. You
can also use a length specifier to control the number of characters
printed.

Jun 27 '08 #17
santosh <sa*********@gmail.comwrites:
arnuld wrote:
[...]
> char arr[] = "Richard";
char* pc = "Richard";

Yes. The first declaration creates an array (named arr) of the length
needed to store the string literal "Richard" which is of eight
characters including the terminating newline. Note that the elements of
arr are subsequently modifiable, as you have not const qualified it.
It's identical to any other char array, merely initialised in a
slightly special manner.
You mean the terminating null character ('\0'), not newline.

--
Keith Thompson (The_Other_Keith) <ks***@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 27 '08 #18
Keith Thompson wrote:
santosh <sa*********@gmail.comwrites:
>arnuld wrote:
[...]
>> char arr[] = "Richard";
char* pc = "Richard";

Yes. The first declaration creates an array (named arr) of the length
needed to store the string literal "Richard" which is of eight
characters including the terminating newline. Note that the elements
of arr are subsequently modifiable, as you have not const qualified
it. It's identical to any other char array, merely initialised in a
slightly special manner.

You mean the terminating null character ('\0'), not newline.
Oops yes. Thanks for the correction.

Jun 27 '08 #19
arnuld <No****@NoPain.Romewrites:
[...]
void print_line( char* line )
{
printf("%s\n", *line++);
}

================== OUTPUT ======================
[arnuld@raj C]$ gcc -ansi -pedantic -Wall -Wextra 7-6.c
7-6.c: In function `print_line':
7-6.c:88: warning: format argument is not a pointer (arg 2)
[...]

You've modified your print_line function, but I'm not sure you
understand what was wrong with the original one.

printf with a "%s" format requires a char* argument; the argument
needs to point to a string (i.e., to the first element of an array of
characters terminated by '\0').

The expression ``line'' is of type char*, so this:

printf("%s\n", line);

would have been ok. But the expression ``*line'' or ``*line++'' is of
type char, so your printf call:

printf("%s\n", *line++);

is invalid. Your compiler was even kind enough to warn you about it.

It's as if you had written:

char c = 'x';
printf("%s\n", c);

What probably happens is that the printf function tries to grab the
pointer value that it assumes you passed it; it instead grabs a
character value and perhaps some adjacent garbage, and treats it as a
pointer. That's just one possibility; the behavior is completely
undefined. Kaboom.

--
Keith Thompson (The_Other_Keith) <ks***@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 27 '08 #20
On Mon, 21 Apr 2008 16:50:49 +0200, edwin ng wrote:
You are still not seeing it ?
If you read line1 with success you will NOT read line2.
:\

Now I see it

I just changed the "while" condition to:

while( fgets( line1, ARRSIZE, pf1 ) && fgets( line2, ARRSIZE, pf2 ) )
and "if" condition to:

if( strcmp( p1, p2 ) )
it works fine now. Thanks

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

Jun 27 '08 #21
On Mon, 21 Apr 2008 16:04:35 +0100, Ben Bacarisse wrote:

This does not do what you think it does. In C, the following is
perfectly correct:

if (x == 0 || y/x 1)

y/x will never be evaluated when x == 0 because the second part of the
'||' is not evaluated when the first part is found to be true
(non-zero). In your case, the second file is never read until first
file read *fails*. This is, absolutely, not what you wanted to
happen.

Thanks for this example.

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

Jun 27 '08 #22
arnuld <No****@NoPain.Romewrites:
>On Mon, 21 Apr 2008 16:50:49 +0200, edwin ng wrote:
>You are still not seeing it ?
If you read line1 with success you will NOT read line2.

:\

Now I see it

I just changed the "while" condition to:

while( fgets( line1, ARRSIZE, pf1 ) && fgets( line2, ARRSIZE, pf2 ) )
and "if" condition to:

if( strcmp( p1, p2 ) )
it works fine now. Thanks
Really? What if one file is a prefix of the other? I'd expect that
you'd have to change more than you say you changed.

--
Ben.
Jun 27 '08 #23
On Tue, 22 Apr 2008 13:17:25 +0100, Ben Bacarisse wrote:
Really? What if one file is a prefix of the other?
I tested that too and it works fine :)

I'd expect that you'd have to change more than you say you changed.

oops!, may be I did ;). I did not remember actually:

http://dpaste.com/46253/

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

Jun 27 '08 #24
arnuld <Go**********************@gmail.comwrites:
>On Tue, 22 Apr 2008 13:17:25 +0100, Ben Bacarisse wrote:
>Really? What if one file is a prefix of the other?

I tested that too and it works fine :)
Does the smiley mean, that it does not work?
>I'd expect that you'd have to change more than you say you changed.


oops!, may be I did ;). I did not remember actually:

http://dpaste.com/46253/
Fails for me when one file is a prefix of the other :-)

--
Ben.
Jun 27 '08 #25
On Tue, 22 Apr 2008 14:21:31 +0100, Ben Bacarisse wrote:
Does the smiley mean, that it does not work?
:D

no, it meant the program works.

Fails for me when one file is a prefix of the other :-)

your definition of prefix could be different but program, must not
fail. post contents of files on dpaste. I will check them and fix the
program.

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

Jun 27 '08 #26
arnuld <Go**********************@gmail.comwrites:
>On Tue, 22 Apr 2008 14:21:31 +0100, Ben Bacarisse wrote:
Fails for me when one file is a prefix of the other :-)

your definition of prefix could be different but program, must not
fail. post contents of files on dpaste. I will check them and fix the
program.
file A: file B:
-----------------------
abc abc
def def
ghi

so file A has one more line than B but otherwise they are the same.
The code you posted does not report a difference between them and it
should.

--
Ben.
Jun 27 '08 #27
On Tue, 22 Apr 2008 15:52:51 +0100, Ben Bacarisse wrote:
file A: file B:
-----------------------
abc abc
def def
ghi
so file A has one more line than B but otherwise they are the same.
The code you posted does not report a difference between them and it
should.
yes, you are right. There is problem with the while() condition. What to
do about it ?
I thought of adding NULL check in a new <ifcondition but I am not
sure whether its a good idea:

/* compare 2 files */
void compare_files( FILE* pf1, FILE* pf2 )
{
char line1[ARRSIZE];
char line2[ARRSIZE];
const char *begin_line1, *begin_line2, *p1, *p2;
while( (p1 = fgets( line1, ARRSIZE, pf1 )) && (p2 = fgets( line2, ARRSIZE, pf2 )) )
{
begin_line1 = line1;
begin_line2 = line2;

if( strcmp( p1, p2 ) )
{
puts( begin_line1);
printf(" ------------------- \n");
puts( begin_line2);
return;
}
}

if( !p1 || !p2 )
{
/* print lines here */

}

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

Jun 27 '08 #28
arnuld <Go**********************@gmail.comwrites:
>On Tue, 22 Apr 2008 15:52:51 +0100, Ben Bacarisse wrote:
>file A: file B:
-----------------------
abc abc
def def
ghi
<snip>
I thought of adding NULL check in a new <ifcondition but I am not
sure whether its a good idea:

/* compare 2 files */
void compare_files( FILE* pf1, FILE* pf2 )
{
char line1[ARRSIZE];
char line2[ARRSIZE];
const char *begin_line1, *begin_line2, *p1, *p2;
while( (p1 = fgets( line1, ARRSIZE, pf1 )) && (p2 = fgets( line2, ARRSIZE, pf2 )) )
{
begin_line1 = line1;
begin_line2 = line2;

if( strcmp( p1, p2 ) )
{
puts( begin_line1);
printf(" ------------------- \n");
puts( begin_line2);
return;
}
}

if( !p1 || !p2 )
{
/* print lines here */

}
Not quite right. It is tricky to cover all the cases -- when pf1 runs
out, p2 will contain the last thing that was put in it (which might be
nothing at all). I would force the reading of pairs of lines. &&
does not do that for you.

--
Ben.
Jun 27 '08 #29
On Tue, 22 Apr 2008 16:48:39 +0100, Ben Bacarisse wrote:
>arnuld <Go**********************@gmail.comwrites:
> if( !p1 || !p2 )
{
/* print lines here */
}
Not quite right. It is tricky to cover all the cases -- when pf1 runs
out, p2 will contain the last thing that was put in it (which might be
nothing at all). I would force the reading of pairs of lines. && does
not do that for you.

ok, I can force the reading of lines before while() and then I also need a
new while() loop to keep on reading till the NULL occurs.


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

Jun 27 '08 #30
On Tue, 22 Apr 2008 15:52:51 +0100, Ben Bacarisse wrote:
file A: file B:
-----------------------
abc abc
def def
ghi

so file A has one more line than B but otherwise they are the same.
The code you posted does not report a difference between them and it
should.

I came-up with this alternative code works the same way:
while( 1 )
{
p1 = fgets( line1, ARRSIZE, pf1 );
p2 = fgets( line2, ARRSIZE, pf2 );

begin_line1 = p1;
begin_line2 = p2;

if( strcmp( p1, p2 ) )
{
puts( begin_line1);
printf(" ------------------- \n");
puts( begin_line2);
return;
}
else
{
break;
}
}

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

Jun 27 '08 #31
arnuld said:

<snip>
I came-up with this alternative code works the same way:
while( 1 )
I am well aware that many expert programmers use this construct.
Nevertheless, whenever I see it in the hands of a neophyte, I can't help
but ask myself "how much thought has gone into the design of this loop?"
And the answer is usually "not enough".
{
p1 = fgets( line1, ARRSIZE, pf1 );
p2 = fgets( line2, ARRSIZE, pf2 );

begin_line1 = p1;
begin_line2 = p2;

if( strcmp( p1, p2 ) )
Undefined behaviour on first failure to read a line from either file.

Look, it's easy.

same = 1;
faok = 1;
fbok = 1;
while(same && faok && fbok)
{
if(fgets(line1, ARRSIZE, pf1) == NULL)
{
faok = 0;
}
else if(fgets(line2, ARRSIZE, pf2) == NULL)
{
fbok = 0;
}
else
{
if(strcmp(line1, line2) != 0)
{
same = 0;
}
}
}

Read errors aside, at this point in the program either same is 1 (in which
case they're the same), or faok is 0, in which case your first file is
shorter but up to that point the files match, or fbok is 0, in which case
the second file is shorter but up to that point the files match.

Now mix in the possibility of read error. How will this affect things?

--
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 #32
On Wed, 23 Apr 2008 05:00:55 +0000, Richard Heathfield wrote:
>arnuld said:
while( 1 )
I am well aware that many expert programmers use this construct.
Nevertheless, whenever I see it in the hands of a neophyte, I can't help
but ask myself "how much thought has gone into the design of this loop?"
And the answer is usually "not enough".
:(
Look, it's easy.
no, its too hard to think.

same = 1;
faok = 1;
fbok = 1;
while(same && faok && fbok)
{
if(fgets(line1, ARRSIZE, pf1) == NULL)
{
faok = 0;
}
else if(fgets(line2, ARRSIZE, pf2) == NULL)
{
fbok = 0;
}
else
{
if(strcmp(line1, line2) != 0)
{
same = 0;
}
}
}

Read errors aside, at this point in the program either same is 1 (in which
case they're the same), or faok is 0, in which case your first file is
shorter but up to that point the files match, or fbok is 0, in which case
the second file is shorter but up to that point the files match.

Now mix in the possibility of read error. How will this affect things?

perhaps you could use a less confusing example. In your code, it will
never check the 2nd file once 1st file is NULL and at that time 2nd file
could contain 1 more line or could be NULL. If 2nd file is NULL then both
are same but if it has one more line then they are different and your code
does not check that. I tried it and it doe snot work either, same
semantic-bug that my code has:
void compare_files( FILE* pf1, FILE* pf2 )
{
char line1[ARRSIZE];
char line2[ARRSIZE];
const char *begin_line1, *begin_line2, *p1, *p2;
int files_equal, file1, file2;

files_equal = 1;
file1 = 1;
file2 = 1;

while( files_equal && file1 && file2 )
{
begin_line1 = p1 = fgets( line1, ARRSIZE, pf1 );
begin_line2 = p2 = fgets( line2, ARRSIZE, pf2 );

if( !p1 )
{
file1 = 0;
}
else if( !p2 )
{
file2 = 0;
}
else if( strcmp( p1, p2 ) )
{
files_equal = 0;
}
}

if( !files_equal )
{
puts( begin_line1 );
printf("::::::::::::::::");
puts( begin_line2 );
}
}

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

Jun 27 '08 #33
arnuld said:

<snip>
perhaps you could use a less confusing example.
Well, I did not intend it to be confusing. Nevertheless, I did intend it to
be complete, and you have rightly spotted that it wasn't.
In your code, it will
never check the 2nd file once 1st file is NULL and at that time 2nd file
could contain 1 more line or could be NULL.
Right. So that's a simple check to add, after the loop. If you've run out
of first file, you try to read a line from the second file. If that
doesn't work either because you've run out of file, then the files match.
Otherwise, they don't, and the second file is longer.

--
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 #34
On Wed, 23 Apr 2008 05:26:32 +0000, Richard Heathfield wrote:
Right. So that's a simple check to add, after the loop. If you've run out
of first file, you try to read a line from the second file. If that
doesn't work either because you've run out of file, then the files match.
Otherwise, they don't, and the second file is longer.

no, we have to add 2 checks:

1.) to check if both files are NULL.
2.) to check if the one was not NULL while the other was.
so it works out like this with Segmentation Fault :(

while( files_equal && file1 && file2 )
{
begin_line1 = p1 = fgets( line1, ARRSIZE, pf1 );
begin_line2 = p2 = fgets( line2, ARRSIZE, pf2 );

if( !p1 && !p2 )
{
file1 = file2 = 0;
}
else if( (!p1 && p2) || (!p2 && p1) )
{
files_equal = 0;
}
else if( !p1 )
{
file1 = 0;
}
else if( !p2 )
{
file2 = 0;
}
else if( strcmp( p1, p2 ) )
{
files_equal = 0;
}
}

if( !files_equal )
{
puts( begin_line1 );
printf("::::::::::::::::");
puts( begin_line2 );
}
--
http://lispmachine.wordpress.com/
my email ID is at the above address

Jun 27 '08 #35
On Wed, 23 Apr 2008 05:26:32 +0000, Richard Heathfield wrote:
Right. So that's a simple check to add, after the loop. If you've run out
of first file, you try to read a line from the second file. If that
doesn't work either because you've run out of file, then the files match.
Otherwise, they don't, and the second file is longer.
OK, I am able to run it successfully :). it is messiest code I ever wrote :(

void compare_files( FILE* pf1, FILE* pf2 )
{
char line1[ARRSIZE];
char line2[ARRSIZE];
const char *begin_line1, *begin_line2, *p1, *p2;
int files_equal, file1, file2, eof_file1, eof_file2;

files_equal = 1;
file1 = 1;
file2 = 1;
eof_file1 = 0;
eof_file2 = 0;

while( files_equal && file1 && file2 )
{
begin_line1 = p1 = fgets( line1, ARRSIZE, pf1 );
begin_line2 = p2 = fgets( line2, ARRSIZE, pf2 );

if( !p1 && !p2 )
{
file1 = file2 = 0;
}
else if( (!p1 && p2) )
{
files_equal = 0;
eof_file1 = 1;
}
else if( !p2 && p1 )
{
files_equal = 0;
eof_file2 = 1;
}
else if( strcmp( p1, p2 ) )
{
files_equal = 0;
eof_file1 = eof_file2 = 1;
}
}
if( !files_equal )
{
if( eof_file1 )
{
puts(begin_line2);
}
else if( eof_file2 )
{
puts(begin_line1);
}
else if( eof_file1 && eof_file2 )
{
puts( begin_line1 );
printf("\n-------------------------\n");
puts( begin_line2 );
}
}
--
http://lispmachine.wordpress.com/
my email ID is at the above address

Jun 27 '08 #36
On Apr 23, 9:07*pm, arnuld <GoogleGroupsisFull0fS...@gmail.comwrote:
On Wed, 23 Apr 2008 05:26:32 +0000, Richard Heathfield wrote:
Right. So that's a simple check to add, after the loop. If you've run out
of first file, you try to read a line from the second file. If that
doesn't work either because you've run out of file, then the files match..
Otherwise, they don't, and the second file is longer.

OK, I am able to run it successfully :). it is messiest code I ever wrote :(

void compare_files( FILE* pf1, FILE* pf2 )
{
* char line1[ARRSIZE];
* char line2[ARRSIZE];
* const char *begin_line1, *begin_line2, *p1, *p2;
* int files_equal, file1, file2, eof_file1, eof_file2;

* files_equal = 1;
* file1 = 1;
* file2 = 1;
* eof_file1 = 0;
* eof_file2 = 0;

* while( files_equal && file1 && file2 )
* * {
* * * begin_line1 = p1 = fgets( line1, ARRSIZE, pf1 );
* * * begin_line2 = p2 = fgets( line2, ARRSIZE, pf2 );

* * * if( !p1 && !p2 )
* * * * {
* * * * * file1 = file2 = 0;
* * * * }
* * * else if( (!p1 && p2) )
* * * * {
* * * * * files_equal = 0;
* * * * * eof_file1 = 1;
* * * * }
* * * else if( *!p2 && p1 )
* * * * {
* * * * * files_equal = 0;
* * * * * eof_file2 = 1;
* * * * }
* * * else if( strcmp( p1, p2 ) )
* * * * {
* * * * * files_equal = 0;
* * * * * eof_file1 = eof_file2 = 1;
* * * * }
* * }

* if( !files_equal )
* * {
* * * if( eof_file1 )
* * * * {
* * * * * puts(begin_line2);
* * * * }
* * * else if( eof_file2 )
* * * * {
* * * * * puts(begin_line1);
* * * * }
* * * else if( eof_file1 && eof_file2 )
* * * * {
* * * * * puts( begin_line1 );
* * * * * printf("\n-------------------------\n");
* * * * * puts( begin_line2 );
* * * * }
* * }

--http://lispmachine.wordpress.com/
my email ID is at the above address
Slightly reformatted it looks OK to me:

void compare_files(FILE * pf1, FILE * pf2)
{
char line1[ARRSIZE];
char line2[ARRSIZE];
const char *begin_line1,
*begin_line2,
*p1,
*p2;
int files_equal=1,
file1=1,
file2=1,
eof_file1=0,
eof_file2=0;

while (files_equal && file1 && file2) {
begin_line1 = p1 = fgets(line1, ARRSIZE, pf1);
begin_line2 = p2 = fgets(line2, ARRSIZE, pf2);

if (!p1 && !p2) {
file1 = file2 = 0;
} else if ((!p1 && p2)) {
files_equal = 0;
eof_file1 = 1;
} else if (!p2 && p1) {
files_equal = 0;
eof_file2 = 1;
} else if (strcmp(p1, p2)) {
files_equal = 0;
eof_file1 = eof_file2 = 1;
}
}

if (!files_equal) {
if (eof_file1) {
puts(begin_line2);
} else if (eof_file2) {
puts(begin_line1);
} else if (eof_file1 && eof_file2) {
puts(begin_line1);
printf("\n-------------------------\n");
puts(begin_line2);
}
}
}
Jun 27 '08 #37
arnuld said:
>On Wed, 23 Apr 2008 05:26:32 +0000, Richard Heathfield wrote:
>Right. So that's a simple check to add, after the loop. If you've run
out of first file, you try to read a line from the second file. If that
doesn't work either because you've run out of file, then the files
match. Otherwise, they don't, and the second file is longer.

no, we have to add 2 checks:

1.) to check if both files are NULL.
2.) to check if the one was not NULL while the other was.
Both those checks are described in the statement you quoted, so I don't
understand what you're getting at.

--
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 #38
On Wed, 23 Apr 2008 06:33:07 +0000, Richard Heathfield wrote:
>>Right. So that's a simple check to add, after the loop. If you've run
out of first file, you try to read a line from the second file. If that
doesn't work either because you've run out of file, then the files
match. Otherwise, they don't, and the second file is longer.
Both those checks are described in the statement you quoted, so I don't
understand what you're getting at.

I thought by saying "So that's a simple check to add". Notice the "a
check", I thought <a check == 1 check>

:P


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

Jun 27 '08 #39
Richard Heathfield <rj*@see.sig.invalidwrites:
Look, it's easy.
Well, I think so, but your way is getting bogged down.
same = 1;
faok = 1;
fbok = 1;
while(same && faok && fbok)
{
if(fgets(line1, ARRSIZE, pf1) == NULL)
{
faok = 0;
}
else if(fgets(line2, ARRSIZE, pf2) == NULL)
{
fbok = 0;
}
else
{
if(strcmp(line1, line2) != 0)
{
same = 0;
}
}
}

Read errors aside, at this point in the program either same is 1 (in which
case they're the same), or faok is 0, in which case your first file is
shorter but up to that point the files match, or fbok is 0, in which case
the second file is shorter but up to that point the files match.
I don't think so. If faok is 0 all you know is that file one is shorter
*or the same length* (in terms of lines) as file two.

You will need to read file two outside the loop to determine if it has
also run out. Now, that may have been your plan (you do not show the
tests at the end of the loop) but it seem way too complex to me.

If I were forced to read line by line (rather than char by char) I'd
do it this way:

int read_line(char *buf, size_t sz, FILE *fp)
{
*buf = 0;
return fgets(buf, sz, fp) != NULL;
}

void compare_files(FILE *fp1, FILE *fp2)
{
char l1[ARRSIZE], l2[ARRSIZE];

while (read_line(l1, sizeof l1, fp1) + read_line(l2, sizeof l2, fp2)) {
if (strcmp(l1, l2)) {
fputs(l1, stdout);
puts("-------------------");
fputs(l2, stdout);
return;
}
}
}

The auxiliary function read_line is trivial, but it does exactly
enough to make the various tests (and subsequent output) trivial.

--
Ben.
Jun 27 '08 #40
On Wed, 23 Apr 2008 13:09:36 +0100, Ben Bacarisse wrote:

int read_line(char *buf, size_t sz, FILE *fp)
{
*buf = 0;
return fgets(buf, sz, fp) != NULL;
}

why you did <*buf = 0>

it will only make the 1st element of the array to be a zero, rest are
still same. Why not use this ?

memcopy( buf, '\0', sizeof(buff) / sizeof( buff[0] ))


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

Jun 27 '08 #41
On Wed, 23 Apr 2008 13:09:36 +0100, Ben Bacarisse wrote:

I don't think so. If faok is 0 all you know is that file one is shorter
*or the same length* (in terms of lines) as file two.
You will need to read file two outside the loop to determine if it has
also run out. Now, that may have been your plan (you do not show the
tests at the end of the loop) but it seem way too complex to me.

that was his plan but I did it with all tests inside the loop:
void compare_files( FILE* pf1, FILE* pf2 )
{
char line1[ARRSIZE];
char line2[ARRSIZE];
const char* *p1, *p2;
const char *begin_line1, *begin_line2;

int files_equal;
int file1, file2;
int eof_file1, eof_file2;

files_equal = 1;
file1 = file2 = 1;
eof_file1 = eof_file2 = 0;

while( files_equal && file1 && file2 )
{
begin_line1 = p1 = fgets( line1, ARRSIZE, pf1 );
begin_line2 = p2 = fgets( line2, ARRSIZE, pf2 );

if( !p1 && !p2 )
{
file1 = file2 = 0;
}
else if( (!p1 && p2) )
{
files_equal = 0;
eof_file1 = 1;
}
else if( !p2 && p1 )
{
files_equal = 0;
eof_file2 = 1;
}
else if( strcmp( p1, p2 ) )
{
files_equal = 0;
eof_file1 = eof_file2 = 1;
}
}
if( !files_equal )
{
if( eof_file1 )
{
puts(begin_line2);
}
else if( eof_file2 )
{
puts(begin_line1);
}
else if( eof_file1 && eof_file2 )
{
puts( begin_line1 );
printf("\n-------------------------\n");
puts( begin_line2 );
}
}
}

int read_line(char *buf, size_t sz, FILE *fp) {
*buf = 0;
return fgets(buf, sz, fp) != NULL;
}
}
void compare_files(FILE *fp1, FILE *fp2) {
char l1[ARRSIZE], l2[ARRSIZE];

while (read_line(l1, sizeof l1, fp1) + read_line(l2, sizeof l2,
fp2)) {
if (strcmp(l1, l2)) {
fputs(l1, stdout);
puts("-------------------");
fputs(l2, stdout);
return;
}
}
}
}
The auxiliary function read_line is trivial, but it does exactly enough
to make the various tests (and subsequent output) trivial.
that is exactly what I was looking for and this is the 1st time I have
seen someone using + in a loop :)

I am quite surprised at both how a problem can be solved using 2
different approaches and that people think in very different ways when
they look at a problem.


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

Jun 27 '08 #42
arnuld said:
>On Wed, 23 Apr 2008 13:09:36 +0100, Ben Bacarisse wrote:

>int read_line(char *buf, size_t sz, FILE *fp)
{
*buf = 0;
return fgets(buf, sz, fp) != NULL;
}


why you did <*buf = 0>
So that, in the event of a line *not* being read, buf is still guaranteed
to contain a null-terminated string (provided that fgets hasn't started
reading anything into the array yet when it fails). It isn't perfect, but
it's the best that can be done if we're going to use fgets.
it will only make the 1st element of the array to be a zero, rest are
still same. Why not use this ?

memcopy( buf, '\0', sizeof(buff) / sizeof( buff[0] ))
Partly because memcpy has no 'o' in it, and partly because sizeof can't
magically tell how big an array is from looking at a pointer to its first
element, but mostly because it's a complete waste of time.

--
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 #43
On Thu, 24 Apr 2008 06:01:04 +0000, Richard Heathfield wrote:
>arnuld said:
So that, in the event of a line *not* being read, buf is still
guaranteed to contain a null-terminated string (provided that fgets
hasn't started reading anything into the array yet when it fails). It
isn't perfect, but it's the best that can be done if we're going to use
fgets.
If I am correct, it is not null terminated string, it is that the 1st element
is a null.

Right ?
> memcopy( buf, '\0', sizeof(buff) / sizeof( buff[0] ))
Partly because memcpy has no 'o' in it,
:D

and partly because sizeof can't magically tell how big an array is
from looking at a pointer to its first element,
If there is a function that takes a pointer:

void a_function( char* )

then I can pass either an array name or a pointer to it. If I pass an
array, then I can compute number of elements of array using:

sizeof( array ) / sizeof( array[0] );

inside the function.
but array will never be passed since it will get decayed into the pointer
to its 1st argument.
lets say I pass pointer to array to the function:
char* pc = array;

then can I use the same sizeof() thing to calculate the number of elements
inside the function ?
but mostly because it's a complete waste of time.

well, I will not waste time then ;)

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

Jun 27 '08 #44
arnuld said:
>On Thu, 24 Apr 2008 06:01:04 +0000, Richard Heathfield wrote:
>>arnuld said:
>So that, in the event of a line *not* being read, buf is still
guaranteed to contain a null-terminated string (provided that fgets
hasn't started reading anything into the array yet when it fails). It
isn't perfect, but it's the best that can be done if we're going to use
fgets.

If I am correct, it is not null terminated string, it is that the 1st
element is a null.

Right ?
Half-right. A string is a contiguous sequence of characters terminated by
the first null character, whose length is given by the number of
characters in the string not including the null character. Thus, a string
with a null as its first character is still a string, but it has 0 length.
>> memcopy( buf, '\0', sizeof(buff) / sizeof( buff[0] ))
>Partly because memcpy has no 'o' in it,

:D

>and partly because sizeof can't magically tell how big an array is
from looking at a pointer to its first element,

If there is a function that takes a pointer:

void a_function( char* )

then I can pass either an array name or a pointer to it.
Yes.
If I pass an
array, then I can compute number of elements of array using:

sizeof( array ) / sizeof( array[0] );

inside the function.
No. Try it and see. The only way it's ever going to work is by accident
when your array size is equal to the ratio of your pointer size to your
type size (e.g. an array of four chars on systems where pointers are four
bytes wide). It fails in all other cases.
but array will never be passed since it will get decayed into the pointer
to its 1st argument.
(You mean "first element".) Right, which is why the sizeof thing doesn't do
what you expect when dealing with a parameter.
lets say I pass pointer to array to the function:
char* pc = array;
If you've truly passed a pointer-to-array, then char * isn't a compatible
type.
then can I use the same sizeof() thing to calculate the number of
elements inside the function ?
You can do this:

size_t CalcNumElementsInChar20Array(char (*p)[20])
{
return sizeof *p / sizeof (*p)[0];
}

but what's the point?

--
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 #45
arnuld wrote:

<snip>
If there is a function that takes a pointer:

void a_function( char* )

then I can pass either an array name or a pointer to it. If I pass an
array, then I can compute number of elements of array using:

sizeof( array ) / sizeof( array[0] );

inside the function.
No you can't. The array argument would "decay" to a pointer value,
loosing the associated size information in the process. Applying sizeof
will give you the size of the pointer instead -- not what you want.
Thus you must either pass the size of the array separately to the
function (i.e., as another parameter), or make it available at a known
place (this is not a good option), or encode the size as a part of the
array itself. There may be other more contorted methods too. With C the
only limit is your imagination. You could even write an array package
though it's usage is likely to be slower than using built-in arrays and
the interface would likely be painful without operator overloading.

Try this program and see:

#include <stdio.h>

static void fx(const char a[]) {
printf("sizeof a (in fx): %lu\n", (unsigned long)sizeof a);
return;
}

int main(void) {
const char a[] = "hello world!";
printf("sizeof a (in main): %lu\n", (unsigned long)sizeof a);
fx(a);
return 0;
}
but array will never be passed since it will get decayed into the
pointer to its 1st argument.
Pointer to it's first element you mean.

<snip>

Jun 27 '08 #46
On Thu, 24 Apr 2008 16:25:32 +0500, arnuld <No****@NoPain.comwrote:
>On Wed, 23 Apr 2008 13:09:36 +0100, Ben Bacarisse wrote:

>I don't think so. If faok is 0 all you know is that file one is shorter
*or the same length* (in terms of lines) as file two.
>You will need to read file two outside the loop to determine if it has
also run out. Now, that may have been your plan (you do not show the
tests at the end of the loop) but it seem way too complex to me.


that was his plan but I did it with all tests inside the loop:
void compare_files( FILE* pf1, FILE* pf2 )
{
char line1[ARRSIZE];
char line2[ARRSIZE];
const char* *p1, *p2;
const char *begin_line1, *begin_line2;

int files_equal;
int file1, file2;
int eof_file1, eof_file2;

files_equal = 1;
file1 = file2 = 1;
eof_file1 = eof_file2 = 0;

while( files_equal && file1 && file2 )
{
begin_line1 = p1 = fgets( line1, ARRSIZE, pf1 );
begin_line2 = p2 = fgets( line2, ARRSIZE, pf2 );

if( !p1 && !p2 )
{
file1 = file2 = 0;
}
else if( (!p1 && p2) )
{
files_equal = 0;
eof_file1 = 1;
}
else if( !p2 && p1 )
{
files_equal = 0;
eof_file2 = 1;
}
else if( strcmp( p1, p2 ) )
{
files_equal = 0;
eof_file1 = eof_file2 = 1;
}
}
if( !files_equal )
{
if( eof_file1 )
{
puts(begin_line2);
}
else if( eof_file2 )
{
puts(begin_line1);
}
else if( eof_file1 && eof_file2 )
I think you are missing a couple of !. On the other hand, you could
delete the if clause completely and just go with an else.
> {
puts( begin_line1 );
printf("\n-------------------------\n");
puts( begin_line2 );
}
}
}

>int read_line(char *buf, size_t sz, FILE *fp) {
*buf = 0;
return fgets(buf, sz, fp) != NULL;
}
}
void compare_files(FILE *fp1, FILE *fp2) {
char l1[ARRSIZE], l2[ARRSIZE];

while (read_line(l1, sizeof l1, fp1) + read_line(l2, sizeof l2,
fp2)) {
if (strcmp(l1, l2)) {
fputs(l1, stdout);
puts("-------------------");
fputs(l2, stdout);
return;
}
}
}
}
The auxiliary function read_line is trivial, but it does exactly enough
to make the various tests (and subsequent output) trivial.

that is exactly what I was looking for and this is the 1st time I have
seen someone using + in a loop :)

I am quite surprised at both how a problem can be solved using 2
different approaches and that people think in very different ways when
they look at a problem.

Remove del for email
Jun 27 '08 #47
arnuld <No****@NoPain.comwrites:
>On Wed, 23 Apr 2008 13:09:36 +0100, Ben Bacarisse wrote:
that was his plan but I did it with all tests inside the loop:
I think you are making this much more complex than it is -- and you are
not really doing what you think you are doing.
void compare_files( FILE* pf1, FILE* pf2 )
{
char line1[ARRSIZE];
char line2[ARRSIZE];
const char* *p1, *p2;
Eh? Does you compiler not complain about this later?
const char *begin_line1, *begin_line2;
What are these for?
int files_equal;
int file1, file2;
int eof_file1, eof_file2;

files_equal = 1;
file1 = file2 = 1;
eof_file1 = eof_file2 = 0;
You don't need five flags just to get this to work out!
while( files_equal && file1 && file2 )
{
begin_line1 = p1 = fgets( line1, ARRSIZE, pf1 );
begin_line2 = p2 = fgets( line2, ARRSIZE, pf2 );

if( !p1 && !p2 )
{
file1 = file2 = 0;
}
else if( (!p1 && p2) )
{
files_equal = 0;
eof_file1 = 1;
}
else if( !p2 && p1 )
{
files_equal = 0;
eof_file2 = 1;
}
else if( strcmp( p1, p2 ) )
{
files_equal = 0;
eof_file1 = eof_file2 = 1;
}
}
if( !files_equal )
{
if( eof_file1 )
{
puts(begin_line2);
}
else if( eof_file2 )
{
puts(begin_line1);
}
else if( eof_file1 && eof_file2 )
{
You can't ever get here. You've tied yourself in a logical knot.
puts( begin_line1 );
printf("\n-------------------------\n");
puts( begin_line2 );
}
}
}

>int read_line(char *buf, size_t sz, FILE *fp) {
*buf = 0;
return fgets(buf, sz, fp) != NULL;
}

void compare_files(FILE *fp1, FILE *fp2) {
char l1[ARRSIZE], l2[ARRSIZE];

while (read_line(l1, sizeof l1, fp1) + read_line(l2, sizeof l2,
fp2)) {
if (strcmp(l1, l2)) {
fputs(l1, stdout);
puts("-------------------");
fputs(l2, stdout);
return;
}
}
}
}
The auxiliary function read_line is trivial, but it does exactly enough
to make the various tests (and subsequent output) trivial.

that is exactly what I was looking for and this is the 1st time I have
seen someone using + in a loop :)

I am quite surprised at both how a problem can be solved using 2
different approaches and that people think in very different ways when
they look at a problem.
I think it is a good problem. I am surprised that one of the
solutions on the clc wiki ignores differences in length. For what
it's worth, here is my full solution. I chose slightly different
names and the way main works is different.

/* K&R2, section 7.7, exercise 7.6 */

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

#define ARRSIZE 1000

int files_differ(FILE *, FILE *);

int main(int argc, char **argv)
{
int differ;
FILE *pf1, *pf2 = stdin;

if (argc < 2 || argc 3) {
fprintf(stderr, "Give one or two file names as arguments.\n");
return EXIT_FAILURE;
}
if ((pf1 = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "Unable to open %s.\n", argv[1]);
return EXIT_FAILURE;
}
if (argc 2 && (pf2 = fopen(argv[2], "r")) == NULL) {
fprintf(stderr, "Unable to open %s.\n", argv[2]);
fclose(pf1);
return EXIT_FAILURE;
}

differ = files_differ(pf1, pf2);
fclose(pf1);
fclose(pf2);
return differ ? EXIT_FAILURE : EXIT_SUCCESS;
}

int read_line(char *buf, size_t sz, FILE *fp)
{
*buf = 0;
return fgets(buf, sz, fp) != NULL;
}

int files_differ(FILE *fp1, FILE *fp2)
{
char l1[ARRSIZE], l2[ARRSIZE];

while (read_line(l1, sizeof l1, fp1) + read_line(l2, sizeof l2, fp2)) {
if (strcmp(l1, l2)) {
fputs(l1, stdout);
puts("-------------------");
fputs(l2, stdout);
return 1;
}
}
return 0;
}

--
Ben.
Jun 27 '08 #48
On Thu, 24 Apr 2008 06:16:53 +0000, Richard Heathfield wrote:

Half-right. A string is a contiguous sequence of characters terminated
by the first null character, whose length is given by the number of
characters in the string not including the null character. Thus, a
string with a null as its first character is still a string, but it has
0 length.
ah... I think I will better use this for clarity:

*buf = '\0';

for if I could be reading an array of integers at some other time.
You can do this:

size_t CalcNumElementsInChar20Array(char (*p)[20]) {
return sizeof *p / sizeof (*p)[0];
}
}
but what's the point?

The last sentence is the one I usually ask to the programmers when they
use arrays in C++ for writing Desktop Applications, all the time, or
when they use <void main()in C.

I think I got your point.


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

Jun 27 '08 #49
arnuld wrote:
>On Thu, 24 Apr 2008 06:16:53 +0000, Richard Heathfield wrote:

>Half-right. A string is a contiguous sequence of characters
terminated by the first null character, whose length is given by the
number of characters in the string not including the null character.
Thus, a string with a null as its first character is still a string,
but it has 0 length.

ah... I think I will better use this for clarity:

*buf = '\0';
No. This assigns the value of the character constant '\0' to buf. This
happens to be the same as doing

*buf = 0;

and in a declaration it's the same as

char *buf = NULL;

but I don't suppose that this is what you meant. If you want to assign a
pointer to a null string, do

char *buf = "";

Jun 27 '08 #50

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

12 posts views Thread by Chris Readle | last post: by
16 posts views Thread by Josh Zenker | last post: by
2 posts views Thread by arnuld | last post: by
4 posts views Thread by arnuld | last post: by
16 posts views Thread by arnuld | last post: by
19 posts views Thread by arnuld | last post: by
5 posts views Thread by arnuld | last post: by
16 posts views Thread by arnuld | last post: by
88 posts views Thread by santosh | last post: by
reply views Thread by zhoujie | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.