Cannot find error on my program ( verry basic C stuff )

C

Chakib Benziane

Hi folks,

I'am learning C programming from ANSI_C Reference Manual of Kernighan &
D.Ritchie .
I'm still working on the tutorial chapter , in have some issues with
exercice 1-18 .

The goal is to write a program to remove trailing blanks and tabs from
each line of input, and to delete entirely blank lines.

Here's my source code :

/********************** /

/* Remove trailing blanks and tabs from each line
** not worked yet on removing tabs
*/

#include <stdio.h>

#define MAXLINE 1000 /* max input line length */
#define IN 1
#define OUT 0

/* function prototypes */
int getline (char line[], int maxline);
void clean (char line[], char cleaned[]);

/* prints input lines after removing trailing blanks and tabs */
int main(void)
{
char line[MAXLINE]; /* current line */
char cleaned[MAXLINE]; /* cleaned line */

while (getline (line, MAXLINE)){
clean (line, cleaned);
printf ("\n%s", cleaned);
}
}


/* get new line into an char array */
int getline(char line[], int lim)
{
int c, i;

for (i=0; i < lim - 1 && ((c = getchar()) != EOF) && (c != '\n'); ++i)
line = c;
if (c == '\n'){
line = c;
++i;
line = '\0';
return 1;
}
if (c == EOF)
return 0;

}

void clean(char line[], char cleaned[])
{
int space;
int i;

if (line[0] == ' ')
space == IN;
else
space == OUT;

for (i=0; line != '\0'; ++i){
if (space == OUT)
if (line != ' ')
cleaned = line;
else if (line == ' '){
space == IN;
cleaned = line;
}
else if (space == IN)
if (line != ' '){
cleaned = line;
space == OUT;
}
else if (line == ' ')
;
}
cleaned = line;
}

/*************************************/


The output gives me 8 whatever the input was .
If somebody can help me to resolve this problem it would be great , i
need just to find where's the error not to get the solution to this
probleme as i have the solution book .

Thx in advance and sorry for my poor english

Chakib .B
 
K

Keith Thompson

Chakib Benziane said:
I'am learning C programming from ANSI_C Reference Manual of Kernighan
& D.Ritchie .
I'm still working on the tutorial chapter , in have some issues with
exercice 1-18 .

The goal is to write a program to remove trailing blanks and tabs from
each line of input, and to delete entirely blank lines.

Here's my source code :
[snip]

I haven't taken the time to study your code, but one thing jumped out
at me. In several places, you use "==" (comparison) when you should
use "=" (assignment).

[...]
 
M

Michael Melanson

Hi Chakib,

Keith brings up a good point, and you should definitely check that out
immediately.

If that doesn't solve your problem, I suggest running it through
Valgrind, then developing some test cases for each function. You might
also consider stepping through the code in GDB.

I don't have time to audit your code unfortunately, but hopefully that
will put you on the right track.


Regards,

Michael Melanson
 
J

Jens Thoms Toerring

Chakib Benziane said:
[-- text/plain, encoding 7bit, charset: ISO-8859-1, 100 lines --]
I'am learning C programming from ANSI_C Reference Manual of Kernighan &
D.Ritchie .
I'm still working on the tutorial chapter , in have some issues with
exercice 1-18 .
The goal is to write a program to remove trailing blanks and tabs from
each line of input, and to delete entirely blank lines.
Here's my source code :
/********************** /
/* Remove trailing blanks and tabs from each line
** not worked yet on removing tabs
*/
#include <stdio.h>
#define MAXLINE 1000 /* max input line length */
#define IN 1
#define OUT 0
/* function prototypes */
int getline (char line[], int maxline);
void clean (char line[], char cleaned[]);
/* prints input lines after removing trailing blanks and tabs */
int main(void)
{
char line[MAXLINE]; /* current line */
char cleaned[MAXLINE]; /* cleaned line */
while (getline (line, MAXLINE)){
clean (line, cleaned);
printf ("\n%s", cleaned);
}

Since you promised to return an int you need here

return 0;
}

/* get new line into an char array */
int getline(char line[], int lim)
{
int c, i;
for (i=0; i < lim - 1 && ((c = getchar()) != EOF) && (c != '\n'); ++i)
line = c;


You might end up here with 'c' not being set at all if 'lim' is 1
(or even smaller).
if (c == '\n'){
line = c;
++i;
line = '\0';
return 1;
}
if (c == EOF)
return 0;


And what is supposed to happen if 'c' is neither '\n' nor EOF?
That could happen if the line is too long. Another nitpick: if
the last line in the input isn't terminated by a '\n' you will
report back a value that looks as if nothing had been read. Is
that really what you want?
void clean(char line[], char cleaned[])
{
int space;
int i;

if (line[0] == ' ')
space == IN;
else
space == OUT;

Keith already told you about the porblem with the '=='. This
is a comparison operator, not an assignment which you obviously
want to do here.
for (i=0; line != '\0'; ++i){
if (space == OUT)
if (line != ' ')
cleaned = line;
else if (line == ' '){
space == IN;


Same as above problem with '=='.
cleaned = line;
}
else if (space == IN)


The indentation makes it look as if this 'else' is supposed to
refer to the "outher" if (i.e. 'if (space == OUT)') but that's
not what you got here - it refers to the "inner" if (i.e.
'if (line != ' ')'). Indentation doesn't count for the
compiler, you have to use curly braces to tell it what you
mean.
if (line != ' '){
cleaned = line;
space == OUT;


Same problem with '=='.
}
else if (line == ' ')
;
}
cleaned = line;
}

Regards, Jens
 
B

Ben Bacarisse

Chakib Benziane said:
I'am learning C programming from ANSI_C Reference Manual of Kernighan
& D.Ritchie .
I'm still working on the tutorial chapter , in have some issues with
exercice 1-18 .

The goal is to write a program to remove trailing blanks and tabs from
each line of input, and to delete entirely blank lines.

Here's my source code :

/********************** /

/* Remove trailing blanks and tabs from each line
** not worked yet on removing tabs
*/

#include <stdio.h>

#define MAXLINE 1000 /* max input line length */
#define IN 1
#define OUT 0

/* function prototypes */
int getline (char line[], int maxline);
void clean (char line[], char cleaned[]);

/* prints input lines after removing trailing blanks and tabs */
int main(void)
{
char line[MAXLINE]; /* current line */
char cleaned[MAXLINE]; /* cleaned line */

while (getline (line, MAXLINE)){
clean (line, cleaned);
printf ("\n%s", cleaned);

This must be wrong -- you can't start with a newline. If the input
starts "abc..." the output must start "abc..." not "\nabc...".
}
}


/* get new line into an char array */
int getline(char line[], int lim)

line[] is fine provided you don't get confused by it. line is a
pointer to (and array of) char. Most modern C programmer would write

int getline(char *line, int lim)
{
int c, i;

for (i=0; i < lim - 1 && ((c = getchar()) != EOF) && (c != '\n'); ++i)
line = c;
if (c == '\n'){


c may not be set! The loop can terminate because i >= lim-1 right at
the start and that can mean nothing has been put in c. OK, this won't
happen in your case because lim is big, but if the function can deal
with any limit you need to say so.
line = c;
++i;
line = '\0';
return 1;


Worse, if the loop ends because the limit is hit, c may not be \n and
the buffer won't be properly null-terminated.
}
if (c == EOF)
return 0;

And if the input ends without a newline, the last line will not get
printed.
}

void clean(char line[], char cleaned[])
{
int space;
int i;
if (line[0] == ' ')
space == IN;
else
space == OUT;

I prefer to make "flag" variables like this have a name that reflects
the condition. I would write:

space_seen = line[0] == ' ';

or

last_char_was_space = line[0] == ' ';

and not have IN and OUT.
for (i=0; line != '\0'; ++i){
if (space == OUT)
if (line != ' ')
cleaned = line;
else if (line == ' '){
space == IN;
cleaned = line;
}
else if (space == IN)
if (line != ' '){
cleaned = line;
space == OUT;
}
else if (line == ' ')
;


Sorry but this is very wrong. You have == when you mean = in a few
places and the indentation does match the logic: the

else if (space == IN)

is *not* an alternative to if (space == OUT). You should see if your
editor can help you here. Mine does the indentation for me so I can
see if the "else" belongs to the correct "if".

But really there are worse problems. The plan is simply not right.
You can't remove trailing space this way. Work out how you'd do it on
paper first and then try to write than in C.
}
cleaned = line;


For example, not matter what you've done before, this line means that
the null that ends line is put in the same place in cleaned.
Sometimes the null in "cleaned" *must* be at an index less than the
null in "line".
 
J

jameskuyper

Ben said:
int getline(char line[], int lim)

line[] is fine provided you don't get confused by it. line is a
pointer to (and array of) char. Most modern C programmer would write

int getline(char *line, int lim)

I suppose my modernity is arguable, but I (imperfectly) follow the
convention of writing pointer parameters as
T *param_name for pointers to a single object, while I use T param_name
[] for pointers to the first element of an array. The distinction
doesn't mean anything to the compiler, but it can be a helpful
reminder for human beings.
 
C

Chakib Benziane

OK , thanx to all of you for your advices , i've read all your comments
and i agree that this code is not clean at all lol , however i am trying
to find out how to do the exercises using only things i've learned in
the Tutorial Chapter , and looking for mistakes to fix them before going
to next levels .

I've made some fixes to my program relying on your comments , for
instance i have to work on the getline function in the case of line not
finishing on \n or reaching lim .

I have also fixed the output problem, the program seems respecting the
exercise requests .


**************************

/* Remove trailing blanks and tabs from each line
**
*/

#include <stdio.h>

#define MAXLINE 1000 /* max input line length */
#define IN 1
#define OUT 0

/* function prototypes */
int getline (char line[], int maxline);
void clean (char line[], char cleaned[]);

/* prints input lines after removing trailing blanks and tabs */
int main(void)
{
char line[MAXLINE]; /* current line */
char cleaned[MAXLINE]; /* cleaned line */

while (getline (line, MAXLINE)){
clean (line, cleaned);
printf ("\n%s", cleaned);
}
return 0;
}


/* get new line into a char array */
int getline(char line[], int lim)
{
int c;
int l_index; /* line array index */

for (l_index=0; l_index < lim - 1 && ((c = getchar()) != EOF) && (c !=
'\n'); ++l_index)
line[l_index] = c;
if (c == '\n'){
line[l_index] = c;
++l_index;
line[l_index] = '\0';
return 1;
}
if (c == EOF)
return 0;

}

void clean(char line[], char cleaned[])
{
int inspace,tab ;
int l_index, c_index; /* line index and cleaned index */
c_index = 0;
tab = OUT;


if (line[0] == ' ' || line[0] == '\t') /** if there's trailing blanks
or tabs at start of line*/
inspace = IN;
else
inspace = OUT;

for (l_index=0; line[l_index] != '\0'; ++l_index){

printf ("Examining character %d - '%c' space is %s\n", l_index,
line[l_index],inspace ? "IN" : "OUT"); /* debugging statments*/

if (inspace)
if (line[l_index] == ' ' || line[l_index] == '\t')
;
else {
cleaned[c_index] = line[l_index];
++c_index;
inspace = OUT;
}
else /* if out space */
if (line[l_index] != ' ' && line[l_index] != '\t'){ /* next char is
not blank or tab*/
cleaned[c_index] = line[l_index];
++c_index;
}
else if (line[l_index] == '\t'){
cleaned[c_index] = ' ';
inspace = IN;
++c_index;
}
else {
inspace = IN;
cleaned[c_index] = line[l_index];
++c_index;
}
}

cleaned[c_index] = line[l_index];

}


*************************************************





CHAKIB . B
PARIS , FRANCE
(e-mail address removed)
 
C

Chakib Benziane

OK , thanx to all of you for your advices , i've read all your comments
and i agree that this code is not clean at all lol , however i am trying
to find out how to do the exercises using only things i've learned in
the Tutorial Chapter , and looking for mistakes to fix them before going
to next levels .

I've made some fixes to my program relying on your comments .

I have also fixed the output problem, but i'm not sure if the program
meets the exercise requirements


**************

/* Remove trailing blanks and tabs from each line
**
*/

#include <stdio.h>

#define MAXLINE 1000 /* max input line length */
#define IN 1
#define OUT 0

/* function prototypes */
int getline (char line[], int maxline);
void clean (char line[], char cleaned[]);

/* prints input lines after removing trailing blanks and tabs */
int main(void)
{
char line[MAXLINE]; /* current line */
char cleaned[MAXLINE]; /* cleaned line */

while (getline (line, MAXLINE)){
clean (line, cleaned);
printf ("%s", cleaned);
}
return 0;
}


/* get new line into a char array */
int getline(char line[], int lim)
{
int c;
int l_index; /* line array index */

for (l_index=0; l_index < lim - 1 && ((c = getchar()) != EOF) && (c !=
'\n'); ++l_index)
line[l_index] = c;
if (c == '\n'){
line[l_index] = c;
++l_index;
line[l_index] = '\0';
return 1;
}
if (c == EOF)
return 0;

}

void clean(char line[], char cleaned[])
{
int inspace,tab ;
int l_index, c_index; /* line index and cleaned index */
c_index = 0;
tab = OUT;


if (line[0] == ' ' || line[0] == '\t') /** if there's trailing blanks
or tabs at start of line*/
inspace = IN;
else
inspace = OUT;

for (l_index=0; line[l_index] != '\0'; ++l_index){

/*printf ("Examining character %d - '%c' space is %s\n", l_index,
line[l_index],inspace ? "IN" : "OUT"); /* debugging statments */

if (inspace)
if (line[l_index] == ' ' || line[l_index] == '\t')
;
else {
cleaned[c_index] = line[l_index];
++c_index;
inspace = OUT;
}
else /* if out space */
if (line[l_index] != ' ' && line[l_index] != '\t'){ /* next char is
not blank or tab*/
cleaned[c_index] = line[l_index];
++c_index;
}
else if (line[l_index] == '\t'){
cleaned[c_index] = ' ';
inspace = IN;
++c_index;
}
else {
inspace = IN;
cleaned[c_index] = line[l_index];
++c_index;
}
}

cleaned[c_index] = line[l_index];

}
*************************
 
B

Ben Bacarisse

You seem to be multi-posting. It is much wiser to stick to one group
(this one is the most topical) or to cross-post (look it up if you
don't know the difference) when you are sure that your post belongs in
two places.
 
J

Jens Thoms Toerring

Chakib Benziane said:
OK , thanx to all of you for your advices , i've read all your comments
and i agree that this code is not clean at all lol , however i am trying
to find out how to do the exercises using only things i've learned in
the Tutorial Chapter , and looking for mistakes to fix them before going
to next levels .
I've made some fixes to my program relying on your comments .
I have also fixed the output problem, but i'm not sure if the program
meets the exercise requirements
/* Remove trailing blanks and tabs from each line
**
*/
#include <stdio.h>
#define MAXLINE 1000 /* max input line length */
#define IN 1
#define OUT 0
/* function prototypes */
int getline (char line[], int maxline);
void clean (char line[], char cleaned[]);
/* prints input lines after removing trailing blanks and tabs */

If that are the specs then the program isn't doing what it's
supposed to do - it removes leading tabs and blanks and if there
are trailing blanks or tabs it leaves a space at the end of the
line.
int main(void)
{
char line[MAXLINE]; /* current line */
char cleaned[MAXLINE]; /* cleaned line */
while (getline (line, MAXLINE)){
clean (line, cleaned);
printf ("%s", cleaned);
}
return 0;
}

/* get new line into a char array */
int getline(char line[], int lim)
{
int c;
int l_index; /* line array index */
for (l_index=0; l_index < lim - 1 && ((c = getchar()) != EOF) && (c !=
'\n'); ++l_index)
line[l_index] = c;

You still don't address the problem that the loop may never
be executed (when 'lim' is 1 or less) and then 'c' being left
uninitialized. That's not a real problem here (since the
function is always called with 'lim' set to 'MAXLINE' but if
you re-use the function in a different context that might be
different.
if (c == '\n'){
line[l_index] = c;
++l_index;
line[l_index] = '\0';
return 1;
}
if (c == EOF)
return 0;

And you're also still missing the case that the last value
you got was neither EOF nor '\n' - that will happen if the
buffer for reading in a line is too short to hold a complete
line. You also throw away the last line of a file if it
doesn't end in a '\n'.
void clean(char line[], char cleaned[])
{
int inspace,tab ;
int l_index, c_index; /* line index and cleaned index */
c_index = 0;
tab = OUT;
if (line[0] == ' ' || line[0] == '\t') /** if there's trailing blanks
or tabs at start of line*/

The word 'trailing' means "at the end", so "trailing blanks at the
start of the line" doesn't make much sense;-)
inspace = IN;
else
inspace = OUT;
for (l_index=0; line[l_index] != '\0'; ++l_index){

/*printf ("Examining character %d - '%c' space is %s\n", l_index,
line[l_index],inspace ? "IN" : "OUT"); /* debugging statments */
if (inspace)
if (line[l_index] == ' ' || line[l_index] == '\t')
;
else {

Why not simplify this to

if ( line[ l_index ] != ' ' && line[ l_index ] != '\t' )
{

and get rid of the empty statement after the 'if'?
cleaned[c_index] = line[l_index];
++c_index;
inspace = OUT;
}

else /* if out space */

Ok, you got away without extra curly braces because there can't
be two 'else' after each other, but I would consider it prudent
to use the extra pairs of curlies to enclose this and also the
following block. Otherwise you might make some small change of
the code and suddenly hell breaks lose since they then might
be needed...
if (line[l_index] != ' ' && line[l_index] != '\t'){ /* next char is
not blank or tab*/
cleaned[c_index] = line[l_index];
++c_index;
}
else if (line[l_index] == '\t'){
cleaned[c_index] = ' ';
inspace = IN;
++c_index;
}
else {
inspace = IN;
cleaned[c_index] = line[l_index];
++c_index;
}
}

cleaned[c_index] = line[l_index];

}
Regards, Jens
 
F

Flash Gordon

Chakib said:
OK , thanx to all of you for your advices , i've read all your comments
and i agree that this code is not clean at all lol , however i am trying
to find out how to do the exercises using only things i've learned in
the Tutorial Chapter , and looking for mistakes to fix them before going
to next levels .

That;s good. However, you should also bare in mind suggestions which use
things not yet introduced.
I've made some fixes to my program relying on your comments .

I have also fixed the output problem, but i'm not sure if the program
meets the exercise requirements


**************

/* Remove trailing blanks and tabs from each line
**
*/

#include <stdio.h>

#define MAXLINE 1000 /* max input line length */
#define IN 1
#define OUT 0

An enum would be better for IN/OUT
enum status { OUT, IN };
/* function prototypes */
int getline (char line[], int maxline);
void clean (char line[], char cleaned[]);

/* prints input lines after removing trailing blanks and tabs */
int main(void)
{
char line[MAXLINE]; /* current line */
char cleaned[MAXLINE]; /* cleaned line */

while (getline (line, MAXLINE)){
clean (line, cleaned);
printf ("%s", cleaned);

Here I would use
fputs(cleaned,stdout);
}
return 0;
}


/* get new line into a char array */
int getline(char line[], int lim)
{
int c;
int l_index; /* line array index */

for (l_index=0; l_index < lim - 1 && ((c = getchar()) != EOF) && (c
!= '\n'); ++l_index)

The above line is rather thong for my tastes...
for (l_index=0;
l_index < lim - 1 && ((c = getchar()) != EOF) &&
(c != '\n');
++l_index)
line[l_index] = c;
if (c == '\n'){
line[l_index] = c;
++l_index;

I would not bother with the increment on a separate line.
line[l_index++] = c;
Note that I moved the ++ to the other side.
line[l_index] = '\0';

Shouldn't you null term terminate the line regardless of whether you had
a newline?
return 1;
}
if (c == EOF)
return 0;

What gets returned if lim was reached?

If you are using gcc and the following options to your command line
-ansi -pedantic -Wall -Wextra
}

void clean(char line[], char cleaned[])
{
int inspace,tab ;

Using an enum you could then replace the above with
enum status inspace,tab;
int l_index, c_index; /* line index and cleaned index */
c_index = 0;
tab = OUT;


if (line[0] == ' ' || line[0] == '\t') /** if there's trailing
blanks or tabs at start of line*/

They are leading if they are at the start of the line, not trailing!
inspace = IN;
else
inspace = OUT;

for (l_index=0; line[l_index] != '\0'; ++l_index){

/*printf ("Examining character %d - '%c' space is %s\n",
l_index, line[l_index],inspace ? "IN" : "OUT"); /* debugging statments */

if (inspace)
if (line[l_index] == ' ' || line[l_index] == '\t')
;
else {
cleaned[c_index] = line[l_index];
++c_index;
inspace = OUT;
}
else /* if out space */
if (line[l_index] != ' ' && line[l_index] != '\t'){ /* next
char is not blank or tab*/
cleaned[c_index] = line[l_index];
++c_index;
}
else if (line[l_index] == '\t'){
cleaned[c_index] = ' ';
inspace = IN;
++c_index;
}
else {
inspace = IN;
cleaned[c_index] = line[l_index];
++c_index;
}

The above looks horribly complex to me. Why not, when you find a tab or
a space, just put a single space in the output line and then do a loop
skipping through the rest of the tabs and spaces? You can have loops
within loops!
}

cleaned[c_index] = line[l_index];

}
*************************
 
C

Chakib Benziane

Hi all ,

As many of you had told me , i made a new algorithm to remove trailing (
after text ) blanks and tabs and clear blank lines .

I tried to respect all your suggestions , it is not complete yet, i
have to figure out how to save a line when EOF is reached .

Thanx to all your comments and Ben i'm sorry for multiposting , i will
stick to this newsgroup as it fits to my topic .


source code : http://rafb.net/p/p6G8A587.html


Chakib .B
 
B

Ben Bacarisse

Chakib Benziane said:
As many of you had told me , i made a new algorithm to remove trailing
( after text ) blanks and tabs and clear blank lines .

I tried to respect all your suggestions , it is not complete yet, i
have to figure out how to save a line when EOF is reached .

Thanx to all your comments and Ben i'm sorry for multiposting , i will
stick to this newsgroup as it fits to my topic .

source code : http://rafb.net/p/p6G8A587.html

Posting code directly is likely to lead to more people looking at it.

I did go look, and you need rethink your idea of using the first char
in the line to store an index. It is a really bad idea -- sorry! It
will cause you all kinds of problems (for example, the value might be
limited to the range -128 to +127) and it stops your program's
components from being re-usable. getline should get a line. clean
should "clean" it (I'd call it trim_trailing_ws but that is a detail).

The basic idea -- start from the end of the line is fine. Just don't
do this by storing something magic in line[0].

When I was learning, I found it useful to keep trying to get simpler
and shorter code. Unless the exercises have been deliberately chosen
to be full of odd special cases, shorter, simpler code is usually
correct. Of course, you can't tell when you've made it as short and
as simple as possible, but trying is valuable.
 
R

Richard Bos

Ben Bacarisse said:
I did go look, and you need rethink your idea of using the first char
in the line to store an index. It is a really bad idea -- sorry!

Oh! Surely not! Does not every expert know that counted strings are
infinitely better than C's broken null-terminated strings, and that only
complete fools do not use a home-brewed counted-string library?

Richard
 
C

Chakib Benziane

Chakib Benziane a écrit :
Hi all ,

As many of you had told me , i made a new algorithm to remove trailing (
after text ) blanks and tabs and clear blank lines .

I tried to respect all your suggestions , it is not complete yet, i
have to figure out how to save a line when EOF is reached .

Thanx to all your comments and Ben i'm sorry for multiposting , i will
stick to this newsgroup as it fits to my topic .


source code : http://rafb.net/p/p6G8A587.html


Chakib .B

Sorry , the link is broken .

Here's the code

/* Remove trailing blanks and tabs from each line
**
*/

#include <stdio.h>

#define MAXLINE 1000 /* max input line length , must be at minimum 4 */


/* function prototypes */
int getline (char line[], int maxline);
int clean (char line[], char cleaned[]);

/* prints input lines after removing trailing blanks and tabs */
int main(void)
{
char line[MAXLINE]; /* current line */
char cleaned[MAXLINE]; /* cleaned line */
int start;
start = 1;

while (getline (line, MAXLINE)){
if (start){ /* if text input starting , print a new line */
printf ("\n");
start = 0;
}

if (clean (line, cleaned))
printf ("%s", cleaned);
else
;
}
return 0;
}


/* get new line into a char array */
int getline(char line[], int lim)
{
int c;
int l_index; /* line array index */

/* lim - 2 : 2 elements reserved for '\n' and '\0' */
/* l_index[0] reserver to a pointer */
for (l_index=1; l_index < lim - 2 && ((c = getchar()) != EOF) && (c !=
'\n'); ++l_index){

line[l_index] = c;
}
if (c == '\n'){
line[l_index] = c;
line[0] = l_index; /* save the location of nl in the first case of
the array */
++l_index;
line[l_index] = '\0';
return 1;
}
if (c == EOF)
return 0; /* looking for a way to save the line even if EOF is
reached ! */

/* If line[] is too short */
if (l_index >= lim - 2){
printf ("\n\n!!!!!! No enough space to run the program ! MAXLINE
defined as %d !!!!!!!\n\n\n",lim);
return 0;
}


}

int clean(char line[], char cleaned[])
{
int l_index; /* line array index */
int c_index; /* cleaned line array index */

if (line[1] == '\n')
return 0;
else {

for (l_index = (line[0] - 1); (l_index > 0) && ( (line[l_index] == '
') || (line[l_index] == '\t')); --l_index)
;
if (l_index <= 0)
return 0;
else {
/* put \n and \0 in the end of the cleaned line */
cleaned[l_index] = '\n';
cleaned[l_index + 1] = '\0';

/*copy every char to the cleaned line */
for (c_index=(l_index - 1) ; (c_index >= 0); --c_index)
cleaned[c_index] = line[c_index + 1];
return 1;
}

}
}
 
C

Chakib Benziane

Ben Bacarisse a écrit :
I did go look, and you need rethink your idea of using the first char
in the line to store an index. It is a really bad idea -- sorry! It
will cause you all kinds of problems (for example, the value might be
limited to the range -128 to +127) and it stops your program's
components from being re-usable. getline should get a line. clean
should "clean" it (I'd call it trim_trailing_ws but that is a detail).

The basic idea -- start from the end of the line is fine. Just don't
do this by storing something magic in line[0].

When I was learning, I found it useful to keep trying to get simpler
and shorter code. Unless the exercises have been deliberately chosen
to be full of odd special cases, shorter, simpler code is usually
correct. Of course, you can't tell when you've made it as short and
as simple as possible, but trying is valuable.

I'm not enough advanced in C programming to know the subtle difference
you're talking about in storing magic number in line[0] or not .
I will , though , try find a work around to not use it .
 
B

Barry Schwarz

On Mon, 30 Mar 2009 11:03:56 +0200, Chakib Benziane

snip
Sorry , the link is broken .

Here's the code

/* Remove trailing blanks and tabs from each line
**
*/

#include <stdio.h>

#define MAXLINE 1000 /* max input line length , must be at minimum 4 */


/* function prototypes */
int getline (char line[], int maxline);
int clean (char line[], char cleaned[]);

/* prints input lines after removing trailing blanks and tabs */
int main(void)
{
char line[MAXLINE]; /* current line */
char cleaned[MAXLINE]; /* cleaned line */
int start;
start = 1;

while (getline (line, MAXLINE)){
if (start){ /* if text input starting , print a new line */
printf ("\n");
start = 0;
}

if (clean (line, cleaned))
printf ("%s", cleaned);
else
;
}
return 0;
}


/* get new line into a char array */
int getline(char line[], int lim)

The value passed in to the function for lim is 1000.
{
int c;
int l_index; /* line array index */

/* lim - 2 : 2 elements reserved for '\n' and '\0' */
/* l_index[0] reserver to a pointer */
for (l_index=1; l_index < lim - 2 && ((c = getchar()) != EOF) && (c !=
'\n'); ++l_index){

line[l_index] = c;
}

Let's assume the user typed in 300 characters.
if (c == '\n'){
line[l_index] = c;
line[0] = l_index; /* save the location of nl in the first case of
the array */

Unless your system has bytes bigger than 8 bits, you cannot store the
current value of l_index (300) in a char.
++l_index;
line[l_index] = '\0';
return 1;
}
if (c == EOF)
return 0; /* looking for a way to save the line even if EOF is
reached ! */

You should be aware that getchar can return EOF for reasons other than
end of file. You might want to use the feof or ferror functions.

At this point:

line[0] does not contain the length
your array of char does not contain a '\n' following the input
your array of char does not contain a '\0' following the input
(which means the array does not contain a string)

Since you return 0, the body of the while loop in main will not be
executed so you will not call clean nor will you print out the last
line.
/* If line[] is too short */
if (l_index >= lim - 2){

At this point, can this if ever be false?
printf ("\n\n!!!!!! No enough space to run the program ! MAXLINE
defined as %d !!!!!!!\n\n\n",lim);
return 0;

You need to distinguish between the error return here and the EOF
return above.
}


}

int clean(char line[], char cleaned[])
{
int l_index; /* line array index */
int c_index; /* cleaned line array index */

if (line[1] == '\n')
return 0;
else {

for (l_index = (line[0] - 1); (l_index > 0) && ( (line[l_index] == '
') || (line[l_index] == '\t')); --l_index)

There is another tab character besides horizontal tab. Do you want to
deal with that also? To deal with all characters that are considered
white space, consider using the isspace function.
;
if (l_index <= 0)
return 0;
else {
/* put \n and \0 in the end of the cleaned line */
cleaned[l_index] = '\n';
cleaned[l_index + 1] = '\0';

/*copy every char to the cleaned line */
for (c_index=(l_index - 1) ; (c_index >= 0); --c_index)
cleaned[c_index] = line[c_index + 1];

Ever here of strcpy (or strncpy)?
 
K

Keith Thompson

Barry Schwarz said:
You should be aware that getchar can return EOF for reasons other than
end of file. You might want to use the feof or ferror functions.

Just to avoid confusion, use feof or ferror *after* checking for EOF,
not instead of checking for EOF. (I'm sure Barry knows this, but the
original poster might not.) See section 12 of the comp.lang.c FAQ,
<http://www.c-faq.com/>.

[...]
Ever here of strcpy (or strncpy)?

Beware: strncpy is not just a counted version of strcpy. It's a good
tool for the job it's designed for, but it's rarely what you want.
It's almost always better just to call strcpy after confirming that
there's enough room.
 
J

JosephKK

Oh! Surely not! Does not every expert know that counted strings are
infinitely better than C's broken null-terminated strings, and that only
complete fools do not use a home-brewed counted-string library?

Richard

Such snarkasm (neologism, (C) 2009 JosephKK in clc, all rights
reserved, no use without attributtion).
 

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

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top