similar Perl data structure?

B

Ben Bacarisse

He's not. Did you read the headers? (I accept that maybe you can't
read them using Google groups.)
I will not post source-code to this newsgroup anymore.

Why not?
 
S

Stefan Ram

Ben Bacarisse said:

I do not like it when someone is making a full-quote of my
post without adding any on-topic text of his own seemingly
just for the purpose to undermine the policies set by my
header lines.

I can avoid this happening to my source code by not posting it
anymore.
 
L

luserXtrog

He's not.  Did you read the headers?  (I accept that maybe you can't
read them using Google groups.)

Oh. Thanks.
I was able to turn them on.
So it's to do with copyright and the hyper-text transfer protocol?
I still don't get it.
Is NNTP more protective because it's more obscure?

Yes. Please continue! I was curious and felt obliged to be honest
about the opinion that was trying to form itself in my head.
I only complain because I want to understand your code but fear it
may take too long. How can I respond to the post after it has
disappeared?
 
B

Ben Bacarisse

I do not like it when someone is making a full-quote of my
post without adding any on-topic text of his own seemingly
just for the purpose to undermine the policies set by my
header lines.

I can avoid this happening to my source code by not posting it
anymore.

Ah, I see. Well, your choice of course, but it seem an inevitable
consequence of posting code to Usenet and one most people accept.
 
L

luserXtrog

  I do not like it when someone is making a full-quote of my
  post without adding any on-topic text of his own seemingly
  just for the purpose to undermine the policies set by my
  header lines.

  I can avoid this happening to my source code by not posting it
  anymore.

Stefan, I sincerely appologise. I promise not to do it again.
I merely clicked reply and started typing. I swear I didn't see
the headers at all. If these must the terms, I will grudgingly
abide.

Please, forgive a moment's haste.
 
S

Stefan Ram

Ben Bacarisse said:
Ah, I see. Well, your choice of course, but it seem an inevitable
consequence of posting code to Usenet and one most people accept.

Most people? This is a time line of the traffic of »de.comp.lang.ALL«:

http://usenet.dex.de/pix/lifeline/de.comp.lang.ALL.png

Google Groups started in 2001. »Most people«, at least many
people, seem to already have abandoned Usenet since then.

(I would have used a time line of »comp.lang.ALL« or »comp.lang.c«,
but I was not aware of where to get one.)
 
F

Franken Sense

In Dread Ink, the Grave Hand of Stefan Ram Did Inscribe:
Most people? This is a time line of the traffic of »de.comp.lang.ALL«:

http://usenet.dex.de/pix/lifeline/de.comp.lang.ALL.png

Google Groups started in 2001. »Most people«, at least many
people, seem to already have abandoned Usenet since then.

(I would have used a time line of »comp.lang.ALL« or »comp.lang.c«,
but I was not aware of where to get one.)

Nicht verzagen, woanders fragen.
--
Frank

Mistakes are a part of being human. Appreciate your mistakes for what they
are: precious life lessons that can only be learned the hard way. Unless
it's a fatal mistake, which, at least, others can learn from.
~~ Al Franken,
 
L

luserXtrog

  Actually it is very easy in C, you just reserve a buffer of
  the appropriate size and then, er, simply read the lines into
  the buffer. And you're done!

  My attempt follows - written in ISO/IEC 9899:1999 (E) C,
  without the need for any additional libraries.

  I have the impression that I made a lot of off-by-1 errors,
  which I hid under some dirty hacks. There also are still some
  redundancies in the code. But I do not have the time for a
  code clean-up right now.

  However, I would be pleased to read how to improve the
  following code.

  For the program to be self-contained, it first /writes/ the file
  to the path »tmp.txt«.

I fail to appreciate the need to write a copy of the file merely
to ascertain its length. Why is this length so vital?
  WARNING: this will overwrite any existing file named »tmp.txt«
  in the current directory.

  »writelines« is used to create the file.
  »getc_count« gets the size of the file to be read.
  »readfile« reads the whole file into a buffer.
  »getlines« fills in the array of lines.
  »printlines« then prints these lines.

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

int getc_count
( const char * const path, size_t * const result )
{ FILE * input = fopen( path, "rb" );
  size_t size = 0;
  int failed = 1;
  int error = 0;
  int overflow = 0;
  if( input )
  { int ch = getc( input );
    while( ch != EOF )
    { if( !++size )overflow = 1, ch = EOF;
      else ch = getc( input ); }
    if( ferror( input ))error = 1;

Do you need to call ferror if the loop terminated
due to overflow?
    if( fclose( input )== 0 && !overflow && !error )failed = 0; }
  *result = size;

Isn't result const?
  return failed; }

int writelines
( char const * const path,
  char const * const * const source,
  size_t const n )

Are all these consts truly necessary?
Can't you simply remember not modify them for the space
of a dozen lines?
{ FILE * const file = fopen( path, "w" );

Here the const appears to necessitate C99's
intermixing of declarations and statements;
without it you could easily conform to C90,
possibly with broader portability.
  int result = -1;
  if( file )
  { for( size_t i = 0; i < n; ++i )
    if
    ( strlen( source[ i ])+ 1 !=
      ( size_t )fprintf( file, "%s\n", source[ i ]))
    { result = 2; break; }

What's 2 mean? Can it be given a name instead?
    if( fclose( file ))result = 3;
    if( result == -1 )result = 0;
    else result = 1; }
  else result = 19;
"?!

  return result; }

int readfile2
( char const * const path, char * * const buffer,
  size_t * const linecount,
  size_t * const size )
{ int result = -1;
  char * const buff = *buffer;
  char * p = buff;

buff appears superfluous.
  size_t s = 0;
  { FILE * input = fopen( path, "r" );
    if( input )
    { int ch = getc( input );
      if( ch == '\n' ){ ch = 0; ++*linecount; }
      if( !++s )result = 8, ch = EOF;
      else if( s >= *size )result = 13, ch = EOF;
      else if( ch != EOF )*p++ = ch;
      while( ch != EOF )
      { ch = getc( input );
        if( ch == '\n' ){ ch = 0; ++*linecount; }
        if( !++s )result = 5, ch = EOF;
        else if( s - 1 > *size )result = 6, ch = EOF;
        else if( ch != EOF )*p++ = ch; }
      if( ferror( input ))result = 7;
      if( fclose( input ))result = 9;
      if( result == -1 )
      { if( !++s )result = 10;
        else if( s - 2 > *size )result = 11;
        else
        { *p++ = 0; result = 0;
          *size = p - buff; }}}
    else result = 12; }
  return result; }

int readfile1
( char const * const path, char * * const buffer,
  size_t * const linecount,
  size_t * const size )
{ int result = -1;
  if( *buffer = malloc( *size + 3 ))
  { result = readfile2( path, buffer, linecount, size );
    if( result )
    { free(( void * )*buffer ); *buffer = 0; }}
  else result = 4;
  return result; }

int readfile
( char const * const path, char * * const buffer,
  size_t * const size,
  size_t * const linecount )
{ int result = -1;
  if( !getc_count( path, size ))
  { if( *size + 1 == 0 )result = 14;

what's going on here?
    else if( *size + 2 == 0 )result = 17;
    else if( *size + 3 == 0 )result = 18;
    else result = readfile1( path, buffer, linecount, size ); }
  return result; }

int getlines
( char * buffer, size_t size,
  char const * * * const lines, size_t linecount )

A triple pointer? The interior two indirections of which
are permitted to be modified?
{ int result = -1;
  size_t need = sizeof( char const * )* linecount;
  size_t test = need / sizeof( char const * );
  if( test == linecount )
  { *lines = malloc( need );
    if( *lines )
    { char const * p = buffer;
      int looping = 1;
      size_t i = 0;
      char const * * const l = *lines;
      while( looping )
      { l[ i++ ]= p;
        while( p < buffer + size && *p != 0 )++p;
        ++p;
        if( p < buffer + size + 1 ); else return 15;
        if( i == linecount )break; }
      result = 0; }
    else result = 16; }
  else result = 17;
  return result; }

int printlines
( size_t const linecount, char const * const * lines )
{ for( size_t i = 0; i < linecount; ++i )
  printf( "%s\n", lines[ i ]);
  return 0; }

int main( void )
{ char const * const source[] =
  { "bicycle", "bus", "ferry", "plane", "train" };
  int const writelinesstatus = writelines
  ( "tmp.txt", source, sizeof source / sizeof 0[ source ]);

I'd prefer *source rather than 0[ source ].
  if( writelinesstatus )fprintf( stderr, "%d\n", writelinesstatus );
  else
  { char * buffer = 0; size_t linecount = 0; size_t size = 0;
    int const readfilestatus =
    readfile( "tmp.txt", &buffer, &size, &linecount );
    if( readfilestatus )fprintf( stderr, "%d\n", readfilestatus );
    else
    { char const * * lines = 0;
      int const getlinesstatus =
      getlines( buffer, size, &lines, linecount );
      if( getlinesstatus )fprintf( stderr, "%d\n", getlinesstatus );
      else printlines( linecount, lines );
      if( lines ){ free(( void * )lines ); lines = 0; }
      if( buffer ){ free(( void * )buffer ); buffer = 0; }}}}

I find the style overall inscrutably dense.
What's the purpose for all the magic numbers when main
only checks for a non-zero return?
Isn't main supposed return an int?
You don't need to cast the argument to free.

This was intended to demonstrate how easy the task is in C?
 
L

luserXtrog

/*------------------------------------------------------------------------
 Procedure:     FileToArray
 Purpose:       Reads from the given file all the lines in it and
                returns a pointer to an array of lines. In the given
                int pointer returns the number of lines read, or an
                error code if an error happened.
 Input:         Name of the file to process
                Pointer to an integer that receives the number of
                lines read or an error code, always negative
 Output:        A table of lines or NULL if error

This does not match the code.  Some errors seem to return non-NULL and
some successful calls return NULL.  For example your test program
prints "memory error after reading 0 lines" when the file is empty.


 Errors:        -1 if file could not be opened, or a negative number
                of lines if a memory error happened after reading
                some lines
------------------------------------------------------------------------*/
char **FileToArray(char *file_name,int *linesread)
{
    FILE *f = fopen(file_name,"r");
    int line_counter=0,allocated_lines=0;
    char **line_array=NULL,*linebuf=NULL;
    *linesread = 0;
    if (f == NULL) {
        *linesread = -1;
        return NULL;
    }
    while ((fggets(&linebuf,f)) == 0) {
        if (line_counter >= allocated_lines) {
            char **tmp = realloc(line_array,
                     sizeof(char *)*(line_counter+LINSIZ));

You've copied ggets's design of using additive rather than
multiplicative growth.  That seems odd to me.  Why not multiply?
            if (tmp == NULL) {
                if (line_counter > 0)
                    line_counter = -line_counter;
                break;

Trace through what will happen if this break is taken.  You will try
to realloc with a size calculated from a negative int converted to
a size_t.
            }
            else line_array = tmp;
            allocated_lines += LINSIZ;
        }
        line_array[line_counter++] = linebuf;
    }
    fclose(f);
    *linesread = line_counter;
    if (line_counter < allocated_lines) {
        line_array = realloc(line_array,sizeof(char *)*line_counter);

I believe realloc is permitted to return NULL even when shrinking a
buffer.  This would leak the allocated memory and return NULL even
though nothing has really gone wrong.

Not if you believe 7.20.3.4

The realloc function returns a pointer to the new object (which may
have the same
value as a pointer to the old object), or a null pointer if the new
object could not be
allocated.
 
K

Keith Thompson

luserXtrog said:
Not if you believe 7.20.3.4

The realloc function returns a pointer to the new object (which may
have the same value as a pointer to the old object), or a null
pointer if the new object could not be allocated.

realloc is allowed to fail even when shrinking a buffer, and 7.20.3.4
doesn't say otherwise.

Imagine an implementation in which differently sized objects are
allocated from different heaps (or whatever memory resource is used).
Suppose you've allocated, say, a 1024-byte object, and you want to
shrink it to 512 bytes -- but it happens that no more 512-byte regions
are available for allocation so the reallocation fails. Such an
implementation is not forbidden by the standard.
 
S

Stefan Ram

Ben Bacarisse said:
I know. Are you saying that it is because people quote their code
that have abandoned Usenet?

Web Interface Companies publish Usenet postings, often
decorated with ads without the permission of the authors and
without paying a compensation for the ad revenues to the
Usenet authors. They make the posts available to web users,
who might not understand the structure of Usenet postings and
thus misunderstand levels of quotations and misattribute
authorship of a text. They often do not interpret Cancels and
Supersedes message. The last time I tried to remove posts
using the Web interface of Google, Inc. it was broken, and
didn't work, even after I received a E-Mail message telling me
that those messages were deleted. Sometimes, readers do not
have any means to see the header lines.

Without such Companies, I would not mind that much someone
doing a full-quote without additional on-topic comments of his own,
even though I might have wondered why someone should ever do this.

Moreover, these Companies grant write access to the Usenet via
the World Wide Web to people, who sometimes lack the mental
capabilities to use a proper Newsreader and therefore would
not have written to Usenet otherwise - lowering the average
quality of the posts and hurting the culture of communication.
 
L

luserXtrog

  Web Interface Companies publish Usenet postings, often
  decorated with ads without the permission of the authors and
  without paying a compensation for the ad revenues to the
  Usenet authors. They make the posts available to web users,
  who might not understand the structure of Usenet postings and
  thus misunderstand levels of quotations and misattribute
  authorship of a text. They often do not interpret Cancels and
  Supersedes message. The last time I tried to remove posts
  using the Web interface of Google, Inc. it was broken, and
  didn't work, even after I received a E-Mail message telling me
  that those messages were deleted. Sometimes, readers do not
  have any means to see the header lines.

  Without such Companies, I would not mind that much someone
  doing a full-quote without additional on-topic comments of his own,
  even though I might have wondered why someone should ever do this.

  Moreover, these Companies grant write access to the Usenet via
  the World Wide Web to people, who sometimes lack the mental
  capabilities to use a proper Newsreader and therefore would
  not have written to Usenet otherwise - lowering the average
  quality of the posts and hurting the culture of communication.

Bigotry with paranoia.

If I could delete the code critique I felt guilted into offering,
then I would do so.
Wouldn't it be funny if that's all you ever get?

Your policy is protecting your code from the help it sorely needs.
 
L

luserXtrog

realloc is allowed to fail even when shrinking a buffer, and 7.20.3.4
doesn't say otherwise.

Imagine an implementation in which differently sized objects are
allocated from different heaps (or whatever memory resource is used).
Suppose you've allocated, say, a 1024-byte object, and you want to
shrink it to 512 bytes -- but it happens that no more 512-byte regions
are available for allocation so the reallocation fails.  Such an
implementation is not forbidden by the standard.

What?! Goddamit, is this true??
 
K

Keith Thompson

luserXtrog said:
What?! Goddamit, is this true??

Yes, but it's really nothing to get excited about. Always check the
result of realloc(), as you would for malloc() or calloc(), and don't
store the returned value back in the original pointer object. If it
fails for whatever reason, you still have the original object.

It may well be that no real-world implementation of realloc() ever
fails when shrinking the object; the point is merely that the standard
doesn't require such calls to succeed in all cases.
 
B

BartC

Keith said:
Yes, but it's really nothing to get excited about. Always check the
result of realloc(), as you would for malloc() or calloc(), and don't
store the returned value back in the original pointer object. If it
fails for whatever reason, you still have the original object.

It sounds crazy. If the 512-byte allocation is going to fail, surely it
should just stick with the 1024-byte one?
 
B

Ben Bacarisse

BartC said:
It sounds crazy. If the 512-byte allocation is going to fail, surely
it should just stick with the 1024-byte one?

It is not either or. If a shrinking allocation is going to fail (or
the author has decided not to implement shrinking) an implementation
has two choices: (a) return the buffer or (b) return NULL.

For a logical point of view (b) is the clear winner -- the user get to
keep the buffer but they also get some more information.

The inconvenience to the caller is trivial when "shrink-wrapping" an
allocation since "failure" is perfectly OK -- you just have to do
nothing:

if (temp = realloc(buf, final_size)) buf = temp;
 
L

luserXtrog

BartC said:
Keith said:
[...]
realloc is allowed to fail even when shrinking a buffer, and
7.20.3.4 doesn't say otherwise.
Imagine an implementation in which differently sized objects are
allocated from different heaps (or whatever memory resource is
used). Suppose you've allocated, say, a 1024-byte object, and you
want to shrink it to 512 bytes -- but it happens that no more
512-byte regions are available for allocation so the reallocation
fails. Such an implementation is not forbidden by the standard.
What?! Goddamit, is this true??
Yes, but it's really nothing to get excited about.  Always check the
result of realloc(), as you would for malloc() or calloc(), and don't
store the returned value back in the original pointer object.  If it
fails for whatever reason, you still have the original object.
It sounds crazy. If the 512-byte allocation is going to fail, surely
it should just stick with the 1024-byte one?

It is not either or.  If a shrinking allocation is going to fail (or
the author has decided not to implement shrinking) an implementation
has two choices: (a) return the buffer or (b) return NULL.

For a logical point of view (b) is the clear winner -- the user get to
keep the buffer but they also get some more information.

The inconvenience to the caller is trivial when "shrink-wrapping" an
allocation since "failure" is perfectly OK -- you just have to do
nothing:

  if (temp = realloc(buf, final_size)) buf = temp;

Oh. Well, that's not so terrible, after all.
Thanks for the talk-down, James, Keith, Bart, Richard, Eric, and Ben.
 
D

Dik T. Winter

> Keith Thompson wrote: .... ....
> It sounds crazy. If the 512-byte allocation is going to fail, surely it
> should just stick with the 1024-byte one?

It does, i.e. it does not free the original 1024-byte one.
 

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

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top