malloc for members of a structure and a segmentation fault

J

jbholman

I am pretty new to C and doing my first project in C. I actually read
almost the entire FAQ, but can't seem to figure out this problem.

I have a structure. I have a list of these structures. Inside each
structure, I have two members: a list of strings, and a string.

I have made a sample program below that exhibits the error I am
having. I also read about Valgrind, and used it to tell me where I
was getting the segmentation fault, which is really helpful. The
Valgrind output is below my sample code.

At line 72 (it is labeled below), I use an unitialized value and then,
I try to write to it. I am not sure what I am doing wrong, because I
think I am initializing the value inside my "initialize" routine. Can
anyone help me figure out where I am going wrong.

/********************************** START SAMPLE CODE
**************************************/

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

#define MAXSTRINGS 50
#define MAXSTRING 80
#define MAXSAMPLES 50

/* this is my sample structure. its members are a character poitner,
and a pointer to a character pointer */

struct sample {
char *string; /*substitute will fill in full path_name */
char **stringlist; /*list of arguments to send to execve */
};

int main (void) {

/* function declarations */
struct sample **initialize(struct sample **samplist);
void test (struct sample **samplist);

/* neener is a pointer to a pointer of type sample* */
struct sample **neener;

neener = initialize(neener);
test (neener);
}

struct sample **initialize (struct sample **samplist) {

struct sample *sp;
int i, j;

/* allocate enough space for 50 pointers to sample structures */
samplist = (struct sample **) malloc (MAXSAMPLES * sizeof(struct
sample *));

/* set sp to the the first pointer allocated to samplist */
sp = *samplist;

/* for each of samplist's pointers to sample structures, */
for (i = 0; i < MAXSAMPLES; ++i) {

/* allocate enough space for one pointer to the sample structure
*/
sp = (struct sample *) malloc (sizeof (struct sample));

/* allocate enough space of the for a string */
sp->string = (char *) malloc (MAXSTRING * sizeof (char));

/* allocate enough pointers for the stringlist member's pointer*/
sp->stringlist = (char **) malloc (MAXSTRINGS * sizeof (char *));
/* and for each of stringlists pointers, allocate enough space for
a string*/
for (j = 0; j < MAXSTRINGS; ++j)
*(sp->stringlist + j) = (char *) malloc (MAXSTRING *
sizeof(char));

/* increment sp so it points to samplist's next allocated pointer
*/
++sp;
}
return samplist;
}

void test (struct sample **samplist) {

struct sample *sp;
char *string;
sp = *samplist;
string = "Testing 1 2 3";

*(sp->stringlist + 0) = strcpy(*(sp->stringlist + 0), string); /*
line 72 */
/* segmentation fault */


}
/********************************** END SAMPLE CODE
**************************************/

/********************************** START VALGRIND OUTPUT
*******************************/

==18077== Use of uninitialised value of size 4
==18077== at 0x8048494: test (test.c:72)
==18077== by 0x80483CD: main (test.c:30)
==18077==
==18077== Invalid read of size 4
==18077== at 0x8048494: test (test.c:72)
==18077== by 0x80483CD: main (test.c:30)
==18077== Address 0x4 is not stack'd, malloc'd or (recently) free'd
==18077==
==18077== Process terminating with default action of signal 11
(SIGSEGV)
==18077== Access not within mapped region at address 0x4
==18077== at 0x8048494: test (test.c:72)
==18077== by 0x80483CD: main (test.c:30)
==18077==
==18077== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 11 from
1)
==18077== malloc/free: in use at exit: 214,600 bytes in 2,651 blocks.
==18077== malloc/free: 2,651 allocs, 0 frees, 214,600 bytes allocated.
==18077== For counts of detected errors, rerun with: -v
==18077== searching for pointers to 2,651 not-freed blocks.
==18077== checked 60,224 bytes.

/********************************** END VALGRIND OUTPUT
*******************************/
 
V

vippstar

I am pretty new to C and doing my first project in C. I actually read
almost the entire FAQ, but can't seem to figure out this problem.

#include <stdlib.h>
#include <alloca.h>

Your code fails here. <alloca.h> is not a standard header defined by
the language.

Post to an appropriate newsgroup, if any, or simply read your
implementations documentation, if any.
 
J

jbholman

On Sep 15, 3:47 pm, (e-mail address removed) wrote:
Sorry about this. I removed the the #include <alloca.h> and
recompiled. I used gcc 4.2.3. I still get the same error with
identical results from Valgrind. Sorry again about that.
 
V

vippstar

Sorry about this. I removed the the #include <alloca.h> and
recompiled. I used gcc 4.2.3. I still get the same error with
identical results from Valgrind. Sorry again about that.

<snip top post>

Please don't top post.
See
<http://www.catb.org/jargon/html/T/top-post.html>
<http://www.caliburn.nl/topposting.html>

Now, the next error is when you include <unistd.h> which is also not a
standard header.
Removing all those things that are not standard C, and you'll end up
with a program that doesn't quite do what you want. Instead of doing
that, post in an appropriate newsgroup.
(I don't know where exactly to direct you, but perhaps
<would be appropriate)
 
J

jbholman

Please don't top post.

I also apologize for top posting. I removed the <unistd.h> header as
well. Now my only headers are <stdlib.h>, <stdio.h>, and <string.h>.
I recompiled using gcc. I then got the same error.
 
G

gw7rib

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

#define MAXSTRINGS 50
#define MAXSTRING 80
#define MAXSAMPLES 50

/* this is my sample structure.  its members are a character poitner,
   and a pointer to a character pointer */

struct sample {
  char *string;  /*substitute will fill in full path_name */
  char **stringlist;   /*list of arguments to send to execve */

};

int main (void) {

  /* function declarations */
  struct sample **initialize(struct sample **samplist);
  void test (struct sample **samplist);

  /* neener is a pointer to a pointer of type sample*   */
  struct sample **neener;

  neener = initialize(neener);

This is probably not your problem, but it may show you are confused
about how pointers work. neener doesn't have a specific value before
this line is executed, so there's no point in sending its old value -
which could be anything - to the initialize function.
  test (neener);

}

struct sample **initialize (struct sample **samplist) {

  struct sample *sp;
  int i, j;

Similarly to what I said above - you don't need a value for samplist
at this point. In fact the value it does have is about to be
overwritten.
  /* allocate enough space for 50 pointers to sample structures */
  samplist = (struct sample **) malloc (MAXSAMPLES * sizeof(struct
sample *));

Just to be clear - samplist points to a space which is big enough for
50 pointers to samples. None of these pointers points anywhere yet,
and you haven't yet allocated any space for the samples themselves.
  /* set sp to the the first pointer allocated to samplist   */
  sp = *samplist;

This line makes no sense. As I just said, samplist has space for 50
pointers, but none of them point anywhere yet. So you don't want to
set sp to be the same as the first pointer. Besides, you're about to
overwrite the value of sp with something else...
  /* for each of samplist's pointers to sample structures, */
  for (i = 0; i < MAXSAMPLES; ++i) {

    /* allocate enough space for one pointer to the sample structure
*/
    sp = (struct sample *) malloc (sizeof (struct sample));

    /* allocate enough space of the for a string */
    sp->string = (char *) malloc (MAXSTRING * sizeof (char));

    /* allocate enough pointers for the stringlist member's pointer*/
    sp->stringlist = (char **) malloc (MAXSTRINGS * sizeof (char *));
    /* and for each of stringlists pointers, allocate enough space for
a string*/
    for (j = 0; j < MAXSTRINGS; ++j)
      *(sp->stringlist + j) = (char *) malloc (MAXSTRING *
sizeof(char));

I think you're OK so far...
    /* increment sp so it points to samplist's next allocated pointer
*/
    ++sp;

No! This is where you go wrong. sp points to a sample which you
allocated space for, and which you have filled up. What you need at
this point is:

samplist = sp;

to store the address of this sample in your samplist list.

Remember, sp points to a space big enough for just one sample, because
that's what you said when you malloc'ed it. sp++ will make sp point at
the unallocated space just after it. There's no reason why this space
should be free for you to do things with. And if you don't tell
samplist where your samples are, you'll never find them again.
  }
  return samplist;

}

Hope that helps.
Paul.
 
V

vippstar

I also apologize for top posting. I removed the <unistd.h> header as
well. Now my only headers are <stdlib.h>, <stdio.h>, and <string.h>.
I recompiled using gcc. I then got the same error.


Are you the same person I adviced some time ago not to top-post and he
quoted me with the attributes deleted?
Or it's a common thing among top-posters to delete attributes in their
struggle to keep the reply at the bottom?
Regardless, please leave the attributes untouched.
 
A

Antoninus Twink

I also apologize for top posting. I removed the <unistd.h> header as
well. Now my only headers are <stdlib.h>, <stdio.h>, and <string.h>.
I recompiled using gcc. I then got the same error.

Firstly, please ignore "Vip Star" and "Default Loser". They are trolls
who will happily distract you with irrelevant "corrections", while
ignoring the actual problem...

....which is that you really need to think about the various levels of
indirection you're using with a clearer head.

Compare the code below with yours:


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

#define MAXSTRINGS 50
#define MAXSTRING 80
#define MAXSAMPLES 50


struct sample {
char *string; /*substitute will fill in full path_name */
char **stringlist; /*list of arguments to send to execve */
};

void initialize (struct sample ***samplist);
void test (struct sample **samplist);

int main (void)
{
struct sample **neener;

initialize(&neener);
test (neener);
return 0;
}

void initialize (struct sample ***samplist)
{
int i, j;

*samplist = malloc (MAXSAMPLES * sizeof **samplist);

for (i = 0; i < MAXSAMPLES; ++i) {
*(*samplist+i)=malloc(sizeof **samplist);
(*(*samplist+i))->string=malloc(MAXSTRING);
(*(*samplist+i))->stringlist = malloc (MAXSTRINGS * sizeof(char*));
for (j = 0; j < MAXSTRINGS; ++j)
(*(*samplist+i))->stringlist[j]=malloc(MAXSTRING);
}
}

void test (struct sample **samplist) {

struct sample *sp;
char *string;
sp = *samplist;
string = "Testing 1 2 3";

strcpy(*(sp->stringlist + 0), string);
}
 
R

Richard Tobin

Are you the same person I adviced some time ago not to top-post and he
quoted me with the attributes deleted?
Or it's a common thing among top-posters to delete attributes in their
struggle to keep the reply at the bottom?
Regardless, please leave the attributes untouched.

I think you mean "attributions", not attributes.

-- Richard
 
F

Flash Gordon


This is good advice.
Now, the next error is when you include <unistd.h> which is also not a
standard header.
Removing all those things that are not standard C, and you'll end up
with a program that doesn't quite do what you want. Instead of doing
that, post in an appropriate newsgroup.
(I don't know where exactly to direct you, but perhaps
<news:comp.unix.programmer> would be appropriate)

This is you being wrong.

Removing the non-standard headers gives you a broken program in entirely
standard C with a C problem. So this *is* the correct group. I will
shortly post some appropriate suggestions.
 
F

Flash Gordon

jbholman wrote, On 15/09/08 21:44:
I am pretty new to C and doing my first project in C. I actually read
almost the entire FAQ, but can't seem to figure out this problem.

I have a structure. I have a list of these structures. Inside each
structure, I have two members: a list of strings, and a string.

I have made a sample program below that exhibits the error I am
having. I also read about Valgrind, and used it to tell me where I
was getting the segmentation fault, which is really helpful. The
Valgrind output is below my sample code.

At line 72 (it is labeled below), I use an unitialized value and then,
I try to write to it. I am not sure what I am doing wrong, because I
think I am initializing the value inside my "initialize" routine. Can
anyone help me figure out where I am going wrong.

/********************************** START SAMPLE CODE
**************************************/

#include <stdlib.h>
#include <alloca.h>

This is not only non-standard but also not required for your program.
#include <stdio.h>
#include <string.h>
#include <unistd.h>

This is also non-standard but not required.
#define MAXSTRINGS 50
#define MAXSTRING 80
#define MAXSAMPLES 50

/* this is my sample structure. its members are a character poitner,
and a pointer to a character pointer */

struct sample {
char *string; /*substitute will fill in full path_name */
char **stringlist; /*list of arguments to send to execve */

When you do actually get around to calling execve, *then* your program
will be non-standard and require some non-standard headers. At that
point you will need to start asking on comp.unix.programmer. For now,
however, your question is topical here.
};

int main (void) {

/* function declarations */
struct sample **initialize(struct sample **samplist);
void test (struct sample **samplist);

It would be better to put the above declaration before the start of
main. Where they are the compiler is not required to complain if they
don't match the function definitions.
/* neener is a pointer to a pointer of type sample* */
struct sample **neener;

neener = initialize(neener);

Why are you passing needer as a parameter? See question 4.8 of the
comp.lang.c FAQ at http://c-faq.com/

Note that in the answer it would be better to have "void f(int **ipp)"
for the example rather than "void f(ipp) inst **ipp;".
test (neener);
}

struct sample **initialize (struct sample **samplist) {

struct sample *sp;
int i, j;

/* allocate enough space for 50 pointers to sample structures */
samplist = (struct sample **) malloc (MAXSAMPLES * sizeof(struct
sample *));

You don't need the cast and there is an easier way to use sizeof. Try
samplist = malloc (MAXSAMPLES * sizeof *samplist);
/* set sp to the the first pointer allocated to samplist */
sp = *samplist;

Here is where you start going wrong. sp is set to the current *value* of
*samplist (which is not initialised, so this is wrong), but changing it
will only change the variable sp, not *samplist. What you are doing is
like the following silly example...

int foo;
int barr;
barr = foo;
barr = 10; -- Here you are assuming that foo is changed as well as barr.
/* for each of samplist's pointers to sample structures, */
for (i = 0; i < MAXSAMPLES; ++i) {

/* allocate enough space for one pointer to the sample structure
*/
sp = (struct sample *) malloc (sizeof (struct sample));

This is the point where you expect *samplist to be changed, but of
course it isn't because you have not changed it.

<snip>

You probably have other errors. I recommend that you read through al of
sections 4, 5, 6 and 7 of the comp.lang.c FAQ as you probably have a lot
of other miss-conceptions covered by those sections.
 
J

jbholman

This is probably not your problem, but it may show you are confused
about how pointers work. neener doesn't have a specific value before
this line is executed, so there's no point in sending its old value -
which could be anything - to the initialize function.

I see what you are saying here. In my larger program, I was running a
loop right after the line that reads: 'struct sample **neener'. The
initialize code in the larger program detected whether or not it was
my first time through, and if not, attempted to free the memory and
then reallocate it. (See my updated code at the very end for this) I
hope this is a good strategy. Or maybe there is a better way.
Just to be clear - samplist points to a space which is big enough for
50 pointers to samples. None of these pointers points anywhere yet,
and you haven't yet allocated any space for the samples themselves.


This line makes no sense. As I just said, samplist has space for 50
pointers, but none of them point anywhere yet. So you don't want to
set sp to be the same as the first pointer. Besides, you're about to
overwrite the value of sp with something else...

Your comment above really helps me a lot. I was thinking that I would
make sp point to the first pointer of samplist. Then, by allocating
enough memory to sp for a sample structure, I would be allocating that
to samplist's first pointer. Then, I could increment sp to point to
samplist's next pointer and do it again. But it is now clear (i
think...), that I wasn't allocating memory for samplist's pointers in
the lines below (have to top post here?). I was allocating memory for
the sp pointer, then incrementing sp to point to samplist's next
pointer (leaving the memory just allocated for the last structure
unfreed?), and then allocating memory for a sample structure to the sp
pointer (and not samplist's next pointer) again.
  /* for each of samplist's pointers to sample structures, */
  for (i = 0; i < MAXSAMPLES; ++i) {
    /* allocate enough space for one pointer to the sample structure
*/
    sp = (struct sample *) malloc (sizeof (struct sample));
    /* allocate enough space of the for a string */
    sp->string = (char *) malloc (MAXSTRING * sizeof (char));
    /* allocate enough pointers for the stringlist member's pointer*/
    sp->stringlist = (char **) malloc (MAXSTRINGS * sizeof (char *));
    /* and for each of stringlists pointers, allocate enough space for
a string*/
    for (j = 0; j < MAXSTRINGS; ++j)
      *(sp->stringlist + j) = (char *) malloc (MAXSTRING *
sizeof(char));

I think you're OK so far...
    /* increment sp so it points to samplist's next allocated pointer
*/
    ++sp;

No! This is where you go wrong. sp points to a sample which you
allocated space for, and which you have filled up. What you need at
this point is:

samplist = sp;

to store the address of this sample in your samplist list.


So now, samplist's i'th pointer points to a space large enough for a
sample structure. Right?

Hope that helps.

It helps a lot. Thanks Paul. Gordon's post helped a lot too, but I
started responding to yours before I saw his. I really appreciate
it. I've put my new code below, and included that loop I was talking
about, and added the "free" part to initialize.

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

#define MAXSTRINGS 10
#define MAXSTRING 80
#define MAXSAMPLES 15
#define MAXLOOPS 8

/* this is my sample structure. its members are a character poitner,
and a pointer to a character pointer */
struct sample {
char *string; /*substitute will fill in full path_name */
char **stringlist; /*list of arguments to send to execve */
};

int main (void) {

/* function declarations */
struct sample **initialize(struct sample **samplist);
void test (struct sample **samplist);
void done (struct sample **samplist);

int i;

/* neener is a pointer to a pointer of type sample* */
struct sample **neener;

for (i = 0; i < MAXLOOPS; ++i) {
neener = initialize(neener);
test (neener);
}

done(neener);

}

struct sample **initialize (struct sample **samplist) {

struct sample *sp;
static int first = 1;
int i, j;

if (first != 1) {

for(i = 0; i < MAXSAMPLES; ++i) {
sp = *(samplist + i);
free(sp->string);
for(j = 0; j < MAXSTRINGS; ++j)
free(*(sp->stringlist + j));
free(sp->stringlist);
free(sp);
}
free(samplist);
}

else {
first = 0;
}

/* allocate enough space for 50 pointers to sample structures */
samplist = (struct sample **) malloc (MAXSAMPLES * sizeof(struct
sample *));

/* allocate space for a sample structure to each of samplist's
pointers */
for (i = 0; i < MAXSAMPLES; ++i) {

/* allocate enough space for one pointer to the sample structure
*/
sp = (struct sample *) malloc (sizeof (struct sample));

/* allocate enough space of the for a string */
sp->string = (char *) malloc (MAXSTRING * sizeof (char));

/* allocate enough pointers for the stringlist member's pointer*/
sp->stringlist = (char **) malloc (MAXSTRINGS * sizeof (char *));
/* and for each of stringlist's pointers, allocate enough space
for a string*/
for (j = 0; j < MAXSTRINGS; ++j)
*(sp->stringlist + j) = (char *) malloc (MAXSTRING *
sizeof(char));

/* make samplists i'th pointer point to the newly allocated space
for one sample structure */
*(samplist + i) = sp;
}
return samplist;
}

void test (struct sample **samplist) {

int i, j;
struct sample *sp;
char *string;
sp = *samplist;
string = "Testing 1 2 3";

for (i = 0; i < MAXSAMPLES; ++i) {
sp = *(samplist + i);
sp->string = strcpy(sp->string, string);
for (j = 0; j < MAXSTRINGS; ++j) {
*(sp->stringlist + j) = strcpy(*(sp->stringlist + j), string);
}
}

for (i = 0; i < MAXSAMPLES; ++i) {
sp = *(samplist + i);
printf("Sample %i, string: %s\n", i, sp->string);
for (j = 0; j < MAXSTRINGS; ++j)
printf("Sample %i, stringlist, string %i: %s\n", i, j, *(sp-
stringlist + j));
}
}

void done (struct sample **samplist) {

struct sample *sp;
int i, j;

for(i = 0; i < MAXSAMPLES; ++i) {
sp = *(samplist + i);
free(sp->string);
for(j = 0; j < MAXSTRINGS; ++j)
free(*(sp->stringlist + j));
free(sp->stringlist);
free(sp);
}
free(samplist);
}
 
I

Ian Collins

jbholman said:
I am pretty new to C and doing my first project in C. I actually read
almost the entire FAQ, but can't seem to figure out this problem.

I have a structure. I have a list of these structures. Inside each
structure, I have two members: a list of strings, and a string.
In addition to the other comment, it's a good idea to learn about tools
like lint, which gives a very strong hit as to the cause of your problem:

(26) warning: variable may be used before set: neener

include file is unnecessary
(2) /usr/include/stdio.h

declared global, could be static
initialize x.c(30)
test x.c(67)

use of a pointer that is an uninitialized value
neener defined at x.c(24) :: x.c(26)
allocated at x.c(36) :: x.c(40)
allocated at x.c(36) :: x.c(71)

assigned value never used
sp defined at x.c(32) :: set at x.c(40)
allocated at x.c(47) :: set at x.c(50)
allocated at x.c(53) :: set at x.c(57)
sp defined at x.c(32) :: set at x.c(62)
quadfx> c89 /tmp/x.c -g
quadfx> lint -Nlevel /tmp/x.c
(28) warning: variable may be used before set: neener

include file is unnecessary
(5) /usr/include/unistd.h

include file may be unnecessary
(2) /usr/include/alloca.h
(3) /usr/include/stdio.h

declared global, could be static
initialize x.c(32)
test x.c(69)

use of a pointer that is an uninitialized value
neener defined at x.c(26) :: x.c(28)
allocated at x.c(38) :: x.c(42)
allocated at x.c(38) :: x.c(73)

assigned value never used
sp defined at x.c(34) :: set at x.c(42)
allocated at x.c(49) :: set at x.c(52)
allocated at x.c(55) :: set at x.c(59)
sp defined at x.c(34) :: set at x.c(64)
 
B

Barry Schwarz

This is probably not your problem, but it may show you are confused
about how pointers work. neener doesn't have a specific value before
this line is executed, so there's no point in sending its old value -
which could be anything - to the initialize function.

It is worse than that. Since the value of neener is indeterminate,
the code invokes undefined behavior at this point. Once undefined
behavior is invoked, there is no certainty about any subsequent action
of the program.

Since the value is not needed (as you correctly point out), two
possible solutions are 1) pass NULL and 2) redefine the function to
take no parameters at all.
 
N

Nick Keighley

On 15 Sep 2008 at 21:12, jbholman wrote:


Firstly, please ignore "Vip Star" and "Default Loser". They are trolls
who will happily distract you with irrelevant "corrections", while
ignoring the actual problem...

...which is that you really need to think about the various levels of
indirection you're using with a clearer head.

come on guys! You're actually showing Antoninus Twink to be right!
If you can't be arsed to answer jbholman's, legitimate, question
about a memory access problem then don't answer.

Yes, he shouldn't have top-posted, yes he shouldn't have
used non-standard headers but at least give him
some sort of pointer!

Did I provide an answer? No. But I thought it bizzare
that a newbie(?) had to aplogise three times
before he got some sort of answer. Perhaps the thread
improves later...
 
F

Flash Gordon

Nick Keighley wrote, On 16/09/08 08:45:
come on guys! You're actually showing Antoninus Twink to be right!
If you can't be arsed to answer jbholman's, legitimate, question
about a memory access problem then don't answer.

I did post an answer. I pointed out to vippstar that he was wrong about
the topicality and he accepted this. I also pointed out at what point in
the future the OPs questions would become off topic.
Yes, he shouldn't have top-posted, yes he shouldn't have
used non-standard headers but at least give him
some sort of pointer!

I did.
Did I provide an answer? No. But I thought it bizzare
that a newbie(?) had to aplogise three times
before he got some sort of answer. Perhaps the thread
improves later...

I had not seen any apologies by the OP before I corrected vippstar and
posted a set of corrections explaining where the OP went wrong and also
pointing him at the relevant sections of the FAQ.
 
A

Andrew Poelstra

Quite a few completely irrelevant posts here. First let me say that I
don't care one bit whether anyone top-quotes or bottom-quotes or
whatever and if anyone has to keep going on about this I find it just
childish.

Is this a reply? You didn't quote anything, and I for one have no
clue what on earth you're talking about.
Now some actual help.

Hardly.

<snip>
 
C

CBFalconer

christian.bau said:
Quite a few completely irrelevant posts here. First let me say
that I don't care one bit whether anyone top-quotes or bottom-
quotes or whatever and if anyone has to keep going on about this
I find it just childish. Now some actual help. Not saying what
you are doing wrong, but two things that you are doing that are
very strange. The first one:

You obviously don't try to read anything in a sane order. Nor
quote intelligently. Keep it up and you will be ignored.

A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 

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,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top