Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Understanding some code

Reply
Thread Tools

Understanding some code

 
 
parjit
Guest
Posts: n/a
 
      08-24-2010
Hi

I'm working on a small c project. I need to read lines from stdin, but
because gets is known to be an undefined function I've been given the
code below to use instead. It works fine but I'd like to understand what
its doing and I just find it really confusing.

Can anyone explain to me what's going on here. Thanks.

#include <string.h>
char *safegets(char *buf, int sz)
{
char *r,*p;
return (buf==NULL || sz<1) ? NULL :
sz==1 ? *buf='\0', buf :
!(r=fgets(buf,sz,stdin)) ? r :
(p = strchr(buf, '\n')) ? *p=0, r : r;
}
 
Reply With Quote
 
 
 
 
Seebs
Guest
Posts: n/a
 
      08-24-2010
On 2010-08-24, parjit <> wrote:
> I'm working on a small c project. I need to read lines from stdin, but
> because gets is known to be an undefined function I've been given the
> code below to use instead. It works fine but I'd like to understand what
> its doing and I just find it really confusing.


That is because this code is confusing.

> Can anyone explain to me what's going on here. Thanks.


> #include <string.h>
> char *safegets(char *buf, int sz)
> {
> char *r,*p;
> return (buf==NULL || sz<1) ? NULL :
> sz==1 ? *buf='\0', buf :
> !(r=fgets(buf,sz,stdin)) ? r :
> (p = strchr(buf, '\n')) ? *p=0, r : r;
> }


Okay, first a top-level view: Someone who thinks he's a lot smarter than
he actually is is trying to show off. I used to write code like this,
maybe fifteen or twenty years ago.

Okay, let's start by expanding this a bit:

char *safegets(char *buf, int size)
{
char *temp1, *temp2;
return (buf == NULL || size < 1) ? NULL :
size == 1 ? (*buf = '\0', buf) :
!(temp1 = fgets(buf, size, stdin)) ? temp1 :
(temp2 = strchr(buf, '\n')) ? (*temp2 = 0, temp1) :
temp1;
}

Wow, that's awful.

Quick intro:
return x ? y : z
is basically the same as
if (x) {
return y;
} else {
return z;
}

?: is like an if/then, except you use it as part of an expression,
instead of on statements. So you could do something like
abs_of_x = (x < 0) ? (-1 * x) : (x);
and that's the same effect as
if (x < 0) {
abs_of_x = (-1 * x);
} else {
abs_of_x = x;
}

Let's convert that to if/else:
char *safegets(char *buf, int size);
{
char *temp1, *temp2;
if (buf == NULL || size < 1) {
return NULL;
} else if (size == 1) {
*buf = '\0';
return buf;
} else if (!(temp1 = fgets(buf, size, stdin))) {
return temp1;
} else if (temp2 = strchr(buf, '\n')) {
*temp2 = 0;
return temp1;
} else {
return temp1;
}
}

Okay, this is still crap. I would not approve this code in a tech
review but it's getting legible. Lemme give it some comments:

/* read at most size characters into buf, resulting in a
* null-terminated string. If buf is null or size is not
* at least 1, returns null. If fgets() fails, returns
* null. Otherwise, returns buf, with the first newline
* (if any) replaced with a null byte. Since fgets() in
* theory stops with the newline, that just trims a trailing
* newline.
*/
char *safegets(char *buf, int size);
{
char *temp1, *temp2;
if (buf == NULL || size < 1) {
/* if buf is NULL, or we've said that less than
* one byte is available, return a NULL pointer;
* you give me invalid inputs, I give you invalid
* outputs.
*/
return NULL;
} else if (size == 1) {
/* if we have exactly one byte, it has to be
* the null terminator.
*/
*buf = '\0';
return buf;
} else if (!(temp1 = fgets(buf, size, stdin))) {
/* assign the results of fgets() into a
* new value named temp1. If it's "false"
* (a null pointer), return that newly
* generated null pointer.
*/
return temp1;
} else if (temp2 = strchr(buf, '\n')) {
/* if we find a newline in the string, replace
* it with a null byte. Return the pointer
* returned by fgets. Which is identical to buf,
* mind you.
*/
*temp2 = 0;
return temp1;
} else {
/* there was no newline, but we got a string,
* return it unmodified.
*/
return temp1;
}
}

Ugh. Not very consistent, but at least it makes sense.

char *safegets(char *buf, int size);
{
char *temp1, *temp2;
if (buf == NULL || size < 1) {
return NULL;
} else if (size == 1) {
*buf = '\0';
return buf;
}
temp1 = fgets(buf, size, stdin);
if (!temp1) {
/* fgets failed */
return NULL;
}
temp2 = strchr(buf, '\n');
if (temp2) {
/* found a newline, trim it */
*temp2 = '\0';
}
return buf;
}

That's a little clearer. Still, it's pretty kludgy. Let's see
if we can't make it a little friendlier. At this point, it's more
clear what the goal is: The goal is to write a wrapper around fgets()
which strips the trailing newline. For historical reasons, "gets()"
trims the terminating newline, fgets() doesn't.

Here's a first pass:

char *safegets(char *buf, int size) {
int c;
int count = 1;
char *s = buf;
if (s && size > 0) {
while ((c = getchar()) != EOF &&
c != '\n' &&
count++ < size) {
*s++ = c;
}
*s++ = '\0';
return buf;
} else {
/* invalid arguments */
return NULL;
}
}

Here's my test program:

#include <stdio.h>

char *safegets(char *buf, int size) {
int c;
int count = 1;
char *s = buf;
if (s && size > 0) {
while ((c = getchar()) != EOF &&
c != '\n' &&
count++ < size) {
*s++ = c;
}
*s++ = '\0';
return buf;
} else {
/* invalid arguments */
return NULL;
}
}

int
main(void) {
char buf[10] = { "xxxxxxxxx" };
int i;

printf("doing safegets, length 6:\n");
safegets(buf, 6);
for (i = 0; i < 8; ++i) {
printf("\t[%d]: 0x%02x [%c]\n",
i,
(unsigned char) buf[i],
isprint((unsigned char) buf[i]) ?
buf[i] : '.');
}
printf("[5] or earlier should be 0x00 [.], following should be [x].\n");
return 0;
}

This passed the obvious edge cases:
* values less than 5 characters long
* exactly 5 characters plus a newline
* newline with following characters
* more than 6 characters

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet-
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
 
 
 
Ian Collins
Guest
Posts: n/a
 
      08-24-2010
On 08/25/10 08:51 AM, parjit wrote:
> Hi
>
> I'm working on a small c project. I need to read lines from stdin, but
> because gets is known to be an undefined function I've been given the
> code below to use instead. It works fine but I'd like to understand what
> its doing and I just find it really confusing.
>
> Can anyone explain to me what's going on here. Thanks.
>
> #include<string.h>
> char *safegets(char *buf, int sz)
> {
> char *r,*p;
> return (buf==NULL || sz<1) ? NULL :
> sz==1 ? *buf='\0', buf :
> !(r=fgets(buf,sz,stdin)) ? r :
> (p = strchr(buf, '\n')) ? *p=0, r : r;
> }


If the project contains code like this, run away!

--
Ian Collins
 
Reply With Quote
 
Paul N
Guest
Posts: n/a
 
      08-24-2010
On 24 Aug, 21:51, parjit <nos...@nospam.com> wrote:
> Hi
>
> I'm working on a small c project. I need to read lines from stdin, but
> because gets is known to be an undefined function I've been given the
> code below to use instead. It works fine but I'd like to understand what
> its doing and I just find it really confusing.
>
> Can anyone explain to me what's going on here. Thanks.
>
> #include <string.h>
> char *safegets(char *buf, int sz)
> {
> * *char *r,*p;
> * *return (buf==NULL || sz<1) ? NULL :
> * * *sz==1 ? *buf='\0', buf :
> * * *!(r=fgets(buf,sz,stdin)) ? r :
> * * *(p = strchr(buf, '\n')) ? *p=0, r : r;
> }


I think whoever wrote that code may be messing you about.

If you say something like

return a ? b : c;

then this is the same as:

if (a) return b; else return c;

and because "return" causes the following statements to be missed out,
this is the same as:

if (a) return b;
return c;

So applying that a few times and making a few other small changes, we
get:

char *safegets(char *buf, int sz)
{
char *r,*p;
if (buf==NULL || sz<1) return NULL;
if (sz==1) { buf[0]='\0'; return buf; }
r=fgets(buf,sz,stdin);
if (!r) return r;
p = strchr(buf, '\n');
if (p) { p[0]=0; return r; }
return r;
}

which in turn means:
bail out if buf is NULL or sz (size) is too small
return empty string if there's no space for anything longer
read in one line, or sz-1 characters, whichever is shorter
return NULL if that failed
look for a newline
replace it if you find one
return the string read (same as buf)

Hope that helps.
Paul.
 
Reply With Quote
 
Uno
Guest
Posts: n/a
 
      08-25-2010
Seebs wrote:

> Okay, first a top-level view: Someone who thinks he's a lot smarter than
> he actually is is trying to show off. I used to write code like this,
> maybe fifteen or twenty years ago.
>
> Okay, let's start by expanding this a bit:


Seebs gives himself to be this person who understands the learning
process, indeed can even divine what others are learning.

And, here, he's answering somebody's homework. This is the first
worksheet the prof hands out.

Way to expand The Topic. How about if we call c.l.c. Seebs' blog now?
--
Uno
 
Reply With Quote
 
John Kelly
Guest
Posts: n/a
 
      08-25-2010
On Tue, 24 Aug 2010 18:57:33 -0600, Uno <> wrote:

>Seebs wrote:
>
>> Okay, first a top-level view: Someone who thinks he's a lot smarter than
>> he actually is is trying to show off. I used to write code like this,
>> maybe fifteen or twenty years ago.
>>
>> Okay, let's start by expanding this a bit:

>
>Seebs gives himself to be this person who understands the learning
>process, indeed can even divine what others are learning.
>
>And, here, he's answering somebody's homework. This is the first
>worksheet the prof hands out.
>
>Way to expand The Topic. How about if we call c.l.c. Seebs' blog now?


There's no business like show business.



--
Web mail, POP3, and SMTP
http://www.beewyz.com/freeaccounts.php

 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      08-25-2010
On Tue, 24 Aug 2010 18:57:33 -0600, Uno <> wrote:
>And, here, he's answering somebody's homework. This is the first
>worksheet the prof hands out.


Is it? What university, or course? We could, of course verify this. I
didn't see anything obviously marking it as homework, and I have a really
hard time imagining that being the first of ANYTHING in a C course, because
you generally get through a lot of other stuff before you start working
with nested ?:.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet-
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      08-25-2010
On 8/24/2010 9:36 PM, Seebs wrote:
> On Tue, 24 Aug 2010 18:57:33 -0600, Uno<> wrote:
>> And, here, he's answering somebody's homework. This is the first
>> worksheet the prof hands out.

>
> Is it? What university, or course? We could, of course verify this. I
> didn't see anything obviously marking it as homework, and I have a really
> hard time imagining that being the first of ANYTHING in a C course, because
> you generally get through a lot of other stuff before you start working
> with nested ?:.


... and especially with nested ?: used stupidly. The code as
shown won't compile, and even with the obvious fix it won't survive
code review. It's on a par with `if((!isspace(ch)!=1) == 0)'.

There are two audiences for source code: Compilers and programmers.
The latter is by far the more important; cater to their needs before
worrying about those of the former.

--
Eric Sosman
lid
 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      08-25-2010
On 2010-08-25, Eric Sosman <> wrote:
> ... and especially with nested ?: used stupidly. The code as
> shown won't compile, and even with the obvious fix it won't survive
> code review. It's on a par with `if((!isspace(ch)!=1) == 0)'.


It's really bad. And the interesting thing is, despite Uno's confident
assertion that this is the "first worksheet", I can find no instances
of that code anywhere except this thread.

But mostly, it's just plain too advanced to be a first handout, but
it's very plausible as a cargo cult thing someone would hand you
and tell you it's great. I will say, though. If you look at some
of the code we see in this newsgroup, hypothesizing a teacher who
would hand that out has substantial explanatory power.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet-
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
Uno
Guest
Posts: n/a
 
      08-25-2010
Seebs wrote:
> On 2010-08-25, Eric Sosman <> wrote:
>> ... and especially with nested ?: used stupidly. The code as
>> shown won't compile, and even with the obvious fix it won't survive
>> code review. It's on a par with `if((!isspace(ch)!=1) == 0)'.

>
> It's really bad. And the interesting thing is, despite Uno's confident
> assertion that this is the "first worksheet", I can find no instances
> of that code anywhere except this thread.
>
> But mostly, it's just plain too advanced to be a first handout, but
> it's very plausible as a cargo cult thing someone would hand you
> and tell you it's great. I will say, though. If you look at some
> of the code we see in this newsgroup, hypothesizing a teacher who
> would hand that out has substantial explanatory power.


But you certainly don't think this occured in production code, and this
is the first week of class for people taking computer programming in a
lot of places.

If that place is India, this might be high school stuff.
--
Uno
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Help understanding some C code jake C Programming 12 11-01-2009 01:04 AM
Understanding Some one else's code - beginner Slain C++ 5 07-18-2007 07:27 AM
Need help understanding some JS code. N. Demos Javascript 3 11-21-2005 02:15 PM
a question about understanding some piece of text from a book Tony Johansson C++ 1 05-21-2005 07:44 AM
70-216 need some help understanding IP addressing. =?Utf-8?B?QW5kcmUgU3QtQXViaW4=?= MCSE 10 08-11-2004 06:25 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57