newbie question

N

name

Studied C a while back, and thought I could write this code, but it turns
out I've either forgotten or never understood something important here.

This is supposed to copy one file to another, and word wrap the lines. I
know there's probably a lot of error checking, etc., that should go in the
function 'wordwrap', but I'd like to get it working first.

The code:

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

#define MAXLENGTH 75

void wordwrap(FILE *ifp, FILE *ofp)
{
int c;

char buf1[1000];
char buf2[1000];
/*
int *pbuf1;
int *pbuf2;

pbuf1 = buf1[0];
pbuf2 = &buf2;
*/
int i, j, k;

j = k = 0;

for(i = 0; i < 1000; ++i)
{
while ((c=getc(ifp)) != EOF)
buf1 = c;
printf("%c", buf1);
}
while ((buf2[j] = buf1))
{
if(i == MAXLENGTH -1)
{
if(buf1 != ' ')
{
for(k = i; k > 0 && buf1[k] != ' '; --k);

if(k == 0)
buf2[j] = '\n';
else
buf2[k] = '\n';
}
else
buf2[k] = '\n';
}
++i;
++j;
}
for ( i = 0; buf2 != EOF; ++i)
{
printf("%c", buf2);

}
}

int main(int argc, char *argv[])
{
FILE *fp1;
FILE *fp2;

char *prog = argv[0];

if (argc != 3)
{
printf("Usage: %s: file1 file2\n", prog);
return EXIT_FAILURE;
}
else if ((fp1 = fopen(argv[1], "r")) == NULL)
{
fprintf(stderr, "%s: can't open %s\n", prog, argv[1]);
return EXIT_FAILURE;
}
else if ((fp2 = fopen(argv[2], "w")) == NULL)
{
fprintf(stderr, "%s: can't open %s\n", prog, argv[2]);
return EXIT_FAILURE;
}
else
{
wordwrap(fp1, fp2);
fclose(fp1);
fclose(fp2);
}

if (ferror(fp2))
{
fprintf(stderr, "%s: error writing %s\n", prog, argv[3]);
return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}

Note that I've got pointers to the arrays included but commented out,
because I can't seem to understand a) why they are needed, and b) how to do
that assignment.

What I thought I understood was that what was passed to the function
wordwrap were dereferenced pointers, so that what was going in and out were
the characters in the files, and not the addresses thereof. And so I
thought that I should be able to read them directly, assign them to an
array, manipulate them whilst passing them to another array, and read the
second array out to the second file.

I used the getc and putc routines used in the K&R2 example in chapter 1. I
did so becaue the filecopy routine drops right in place of wordwrap and the
second file is identical to the first. Which is why I figured I could at
least use them to read into the first array and out of the seond.

That function is:

void filecopy(FILE *ifp, FILE *ofp)
{
int c;

while ((c=getc(ifp)) != EOF)
putc(c, ofp);
}

So I thought I could build on that for 'wordwrap'. Wrong (?)

The code compiled (without the array pointers that are commented out). But
note the printf right after the assignment of input to the first array.
What comes out of that are graphical characters I don't understand. Without
that printf statement, the code compiles, but does nothing. The second file
is empty.

So I thought maybe I was wrong and the data coming in were in fact the disk
addresses of the read file (fp1). I can't understand how that works because
those addresses aren't available to memory and so cannot be inspected or
manipulated. Nevertheless, I tried initializing pointers, and botched the
job (obviously). Gcc had this to say:

[wtallman@ansible ~]$ gcc -g -Wall -o f2f f2fwdwrp.c
f2fwdwrp.c: In function wordwrap':
f2fwdwrp.c:16: warning: assignment makes pointer from integer without a cast
f2fwdwrp.c:17: warning: assignment from incompatible pointer type

I have no idea whether or not I'm on the right track here, but what I get
from the printf statement is:

[wtallman@ansible ~]$ f2f testfile testfile11

ã .....and a long string of like characters not reproducable here (at
least not in Jed..). Which is why I wondered if I was looking at disk
addresses, and so needed to put up some pointers to assign to.

Obviously, I am lost here. And after reading K&R2, D&D, H&S, all in the
sections that appeared to be relevant, I'm still lost.

Could someone point me in the direction I need to go to figure this out.

Thanks for reading
 
N

Nick Austin

Studied C a while back, and thought I could write this code, but it turns
out I've either forgotten or never understood something important here.

This is supposed to copy one file to another, and word wrap the lines. I
know there's probably a lot of error checking, etc., that should go in the
function 'wordwrap', but I'd like to get it working first.

The code:

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

#define MAXLENGTH 75

void wordwrap(FILE *ifp, FILE *ofp)
{
int c;

char buf1[1000];
char buf2[1000];
/*
int *pbuf1;
int *pbuf2;

pbuf1 = buf1[0];
pbuf2 = &buf2;
*/
int i, j, k;

j = k = 0;

for(i = 0; i < 1000; ++i)
{
while ((c=getc(ifp)) != EOF)
buf1 = c;
printf("%c", buf1);
}


Try using a debugger to single-step these for and while
loops.

Nick.
 
D

Default User

name said:
Studied C a while back, and thought I could write this code, but it turns
out I've either forgotten or never understood something important here.

This is supposed to copy one file to another, and word wrap the lines. I
know there's probably a lot of error checking, etc., that should go in the
function 'wordwrap', but I'd like to get it working first.

The code:

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

#define MAXLENGTH 75

void wordwrap(FILE *ifp, FILE *ofp)
{
int c;

char buf1[1000];
char buf2[1000];
/*
int *pbuf1;
int *pbuf2;

pbuf1 = buf1[0];
pbuf2 = &buf2;
*/


Neither of the two commented out assignments would be correct. In first,
you are assigning one uninitialized character from buf1 to an int
pointer. That's not what you want.

The second assigns a pointer to an array 1000 of char to an int pointer.
That's a pointer type mismatch. Not what you want.

If pbuf1 and pbuf2 were char * types, then you could assign to them like
so:

char *pbuf1;
char *pbuf2;

pbuf1 = buf1;
pbuf2 = buf2;

Note that I've got pointers to the arrays included but commented out,
because I can't seem to understand a) why they are needed, and b) how to do
that assignment.

See above for the how. The why is usually to use increment operations,
which you can't do with an array.

buf1++; /* NO!! */
pbuf1++ /* Sure! */
What I thought I understood was that what was passed to the function
wordwrap were dereferenced pointers, so that what was going in and out were
the characters in the files, and not the addresses thereof.

Errr, what? What you pass are the file pointers, which are pointers to
an implementation-defined struct of type FILE. When used with the stdio
file functions, you can read or write data from/to the associated files
(assuming these pointers represent correctly opened files). There's no
dereferencing going in.
And so I
thought that I should be able to read them directly, assign them to an
array, manipulate them whilst passing them to another array, and read the
second array out to the second file.

Sounds ok.
I used the getc and putc routines used in the K&R2 example in chapter 1. I
did so becaue the filecopy routine drops right in place of wordwrap and the
second file is identical to the first. Which is why I figured I could at
least use them to read into the first array and out of the seond.

That function is:

void filecopy(FILE *ifp, FILE *ofp)
{
int c;

while ((c=getc(ifp)) != EOF)
putc(c, ofp);
}

Looks ok, a basic filecopy. Probably not the most efficient, but should
work.
So I thought I could build on that for 'wordwrap'. Wrong (?)

Hard to say.
The code compiled (without the array pointers that are commented out). But
note the printf right after the assignment of input to the first array.
What comes out of that are graphical characters I don't understand. Without
that printf statement, the code compiles, but does nothing. The second file
is empty.

You mean this part here, I think:

for(i = 0; i < 1000; ++i)
{
while ((c=getc(ifp)) != EOF)
buf1 = c;
printf("%c", buf1);
}

You have loop problems. Look at your while loop. When does i get
incremented? By the outer loop. Where is the data read? Inner loop. What
happens is that the whole file get stuffed into buf1[0] (first outer
loop pass). After that, each successive outer loop pass increments i,
but no data is read in because ifp is already at EOF.

Get rid of the inner loop, combining the two:

for(i = 0; i < 1000 && (c=getc(ifp)) != EOF; ++i)
{
buf1 = c;
printf("%c", buf1);
}





Brian Rodenborn
 
N

name

name wrote:

Neither of the two commented out assignments would be correct. In first,
you are assigning one uninitialized character from buf1 to an int
pointer. That's not what you want.

The second assigns a pointer to an array 1000 of char to an int pointer.
That's a pointer type mismatch. Not what you want.

If pbuf1 and pbuf2 were char * types, then you could assign to them like
so:

char *pbuf1;
char *pbuf2;

pbuf1 = buf1;
pbuf2 = buf2;

Yep, I got that they were both wrong, and your explanation clarifies gcc's
somewhat laconic comments (laconic only to dummy's like moi... <grin>).

An uniinitialized character, eh? I thought that a pointer to an array
"decayed" into the address of the.... umm, yes. Perhaps the address, but
not the character indexed therein, so maybe pbuf1 = &buf[0] would make more
sense but be utterly useless in any case.

And the second mismatch.. pointer to an array of char doesn't work without
type cast when assigned to an int pointer? Duhhh... LOL!!!! Gawd, when
will I learn to understand the simple sense of what I read?!?

I need a teacher!!! said:
See above for the how. The why is usually to use increment operations,
which you can't do with an array.

buf1++; /* NO!! */
pbuf1++ /* Sure! */

Oh yes, got that. buf1 would be the entire array itself, right? Can't
increment an entire array, what would one increment it to?
Errr, what? What you pass are the file pointers, which are pointers to
an implementation-defined struct of type FILE. When used with the stdio
file functions, you can read or write data from/to the associated files
(assuming these pointers represent correctly opened files). There's no
dereferencing going in.

Yes, I understand that the pointers are passed, but my understanding was
that the pointers were dereferenced when accessed, so that one got the data
that was being pointed to, and not the pointer itself. Implementation
defined struct of type FILE makes sense, and that's what the stdio library
handles, amongst other things.

Let's see if I've got this right: Initializing a pointer, "int *pvariable;";
assigning (referencing?) a pointer, "pvariable = &variable;"; dereferencing a
pointer, "variable = *pvariable;".

Which means that the pointers are passed, and stdio does its magic, and out
pops the data. Thus they are dereferenced within stdio? Guess I've got a
lot to learn now that I've been shown just how much I don't know... said:
Sounds ok.


Looks ok, a basic filecopy. Probably not the most efficient, but should
work.

Straight out of K&R2, and they call the 'while' loop probably *the* most
basic C idiom. Retained that, if little else from my first study.. lol!!
Hard to say.

I think I can with some modifications. It works just fine with stdin and
stdout, so I should be able to hook it in here, I would think. However,
already I see how that could be simplified rather easily....
The code compiled (without the array pointers that are commented out). But
note the printf right after the assignment of input to the first array.
What comes out of that are graphical characters I don't understand. Without
that printf statement, the code compiles, but does nothing. The second file
is empty.

You mean this part here, I think:

for(i = 0; i < 1000; ++i)
{
while ((c=getc(ifp)) != EOF)
buf1 = c;
printf("%c", buf1);
}
Yep!

You have loop problems. Look at your while loop. When does i get
incremented? By the outer loop. Where is the data read? Inner loop. What
happens is that the whole file get stuffed into buf1[0] (first outer
loop pass). After that, each successive outer loop pass increments i,
but no data is read in because ifp is already at EOF.

Get rid of the inner loop, combining the two:

for(i = 0; i < 1000 && (c=getc(ifp)) != EOF; ++i)
{
buf1 = c;
printf("%c", buf1);
}

The cold hard light of day dawns. A while loop inside a for loop? ARGH!!
That should have been obvious! Yep, if(i == 1) buf1 == (one past EOF!).

And of course when I made the change, the original file came tumbling out,
at least up to the 1000th character. Gonna probably change that to INT_MAX.

I think I probably understand more than I feared I did, but with egregious
holes capable of passing Flights of Nasal Daemons! The devil is in the
details, of course, and that's a lot of what lurks in the holes. Simply
have to write lots of code, and then write lots more. Right?
Brian Rodenborn

Thank you, Brian! Your reply was as pleasant and as thorough as I could
possibly want, and if (when?) I have further questions, I will look forward
to your responses!

Thanks again...
 
N

name

for(i = 0; i < 1000; ++i)
{
while ((c=getc(ifp)) != EOF)
buf1 = c;
printf("%c", buf1);
}


Try using a debugger to single-step these for and while
loops.

Nick.


Yep, just got Brian's explanation. Blindingly obvious, of course...lol!!!

'AND' the 'while' loop in the 'for' conditional (without the while, of
course):

for(i = -; i < 1000 && ((c=getc(ifp)) != EOF); ++i)
{
buf = c;
printf("%c", buf1);
}

works just fine.

Thanks for responding!
 
D

Default User

name said:
An uniinitialized character, eh? I thought that a pointer to an array
"decayed" into the address of the.... umm, yes.

No, the NAME of an array, in certain circumstances, is converted to a
pointer to the first element. So for an array of 1000 chars, the name is
converted to a pointer to the first element, that is a pointer to char
(char *).

Using the [] operator is a syntactic sugar for dereferencing the
pointer.

ptr == *(ptr + i)

A pointer to an array is just that.
Perhaps the address, but
not the character indexed therein, so maybe pbuf1 = &buf[0] would make more
sense but be utterly useless in any case.

That is acceptable, although not as common as using the array name. At
any rate, you were trying to assign to int * vars, which is wrong in way
shape or form.
And the second mismatch.. pointer to an array of char doesn't work without
type cast when assigned to an int pointer? Duhhh... LOL!!!! Gawd, when
will I learn to understand the simple sense of what I read?!?

You wouldn't want to cast that, of course.
I need a teacher!!! <sigh>

Or a good book and newsgroup.
Oh yes, got that. buf1 would be the entire array itself, right? Can't
increment an entire array, what would one increment it to?

Arrays are not modifiable lvalues, so you increment or assign to them or
anything like that.

Yes, I understand that the pointers are passed, but my understanding was
that the pointers were dereferenced when accessed, so that one got the data
that was being pointed to, and not the pointer itself.

You're mixing concepts. The FILE * don't have char * type, so they
couldn't yield chars when dereferenced. They would yield the FILE
structs, which you don't want. You aren't dereferencing, you are reading
and writing using standard library functions. How they do that is of no
concern. Magic.

Let's see if I've got this right: Initializing a pointer, "int *pvariable;";
assigning (referencing?) a pointer, "pvariable = &variable;"; dereferencing a
pointer, "variable = *pvariable;".

Referencing really means getting the address of an object. Sort of. You
dereference it to get the object back.
Which means that the pointers are passed, and stdio does its magic, and out
pops the data. Thus they are dereferenced within stdio? Guess I've got a
lot to learn now that I've been shown just how much I don't know... <grin>

Probably, but you don't care. Like I said, some sort of system magic.
Straight out of K&R2, and they call the 'while' loop probably *the* most
basic C idiom. Retained that, if little else from my first study.. lol!!

Right, it's simple. Using other methods could improve efficiency by
taking advantage of system buffering, but getting it right is most
important.

Get rid of the inner loop, combining the two:

for(i = 0; i < 1000 && (c=getc(ifp)) != EOF; ++i)
{
buf1 = c;
printf("%c", buf1);
}

The cold hard light of day dawns. A while loop inside a for loop? ARGH!!
That should have been obvious! Yep, if(i == 1) buf1 == (one past EOF!).


Actually, it will never have had anything assigned to it, so you got
whatever garbage was at that location, represented as a character.

And of course when I made the change, the original file came tumbling out,
at least up to the 1000th character.

Excellent.
Gonna probably change that to INT_MAX.

That's going to be a big buffer, you could have problems with running
out of automatic storage. There are techniques for dealing with files
and optimizing storage. One way is to dynamically allocate the buffer,
resizing as needed. The other is (with a text file) to deal with it a
line at a time.
I think I probably understand more than I feared I did, but with egregious
holes capable of passing Flights of Nasal Daemons! The devil is in the
details, of course, and that's a lot of what lurks in the holes. Simply
have to write lots of code, and then write lots more. Right?

I'd also recommend what another responder said, try to get a debugger.
Thank you, Brian! Your reply was as pleasant and as thorough as I could
possibly want, and if (when?) I have further questions, I will look forward
to your responses!

Sure. Glad to help.


Brian Rodenborn
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Wrap rev 2. 8
Line/word wrap program. 11
Wrap program revised. 5
Command Line Arguments 0
code 34
Blue J Ciphertext Program 2
Scanset 8
creating a testfile for catv 10

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top