Simple code leads to segfault.. help

S

SkyBlue

Hi, can someone explain why the following simple C code segfaulted?
I've stared it for 30mins but couldn't find the problem. Thx in advance

#include <stdio.h>

int main() {

char *one;
char *two;

fgets(one, 200, stdin);
printf("one is %s", one);

fgets(two, 200, stdin);
printf("two is %s", two);

return 0;
}
 
S

Spiros Bousbouras

SkyBlue said:
Hi, can someone explain why the following simple C code segfaulted?
I've stared it for 30mins but couldn't find the problem. Thx in advance

#include <stdio.h>

int main() {

char *one;
char *two;

fgets(one, 200, stdin);
printf("one is %s", one);

fgets(two, 200, stdin);
printf("two is %s", two);

return 0;
}

If you thought that this would work then I'm afraid
you need to go back to your C textbook(s) and study
carefully before you attempt to write another programme
even a toy one.

You never initialize one and two so fgets attempts
to write on some random area of memory. Hence
segfault. What you need is for one and two to point
to some area of memory which has at least 200 bytes
available. How you do that is one of the many reasons
you need to return to your textbooks(s).
you need to go back to your textbooks.
 
J

Joe Wright

SkyBlue said:
Hi, can someone explain why the following simple C code segfaulted?
I've stared it for 30mins but couldn't find the problem. Thx in advance

#include <stdio.h>

int main() {

char *one;
char *two;

fgets(one, 200, stdin);
printf("one is %s", one);

fgets(two, 200, stdin);
printf("two is %s", two);

return 0;
}

You left out too much needed code. Consider..

#include <stdio.h>
#include <stdlib.h>
#define LEN 200

int main(void)
{
char *one;
char *two;

if ((one = malloc(LEN)) == NULL)
puts("Memory Allocation Error."), exit(EXIT_FAILURE);

if ((two = malloc(LEN)) == NULL)
puts("Memory Allocation Error."), exit(EXIT_FAILURE);

fgets(one, LEN, stdin);
printf("one is %s", one);

fgets(two, LEN, stdin);
printf("two is %s", two);

return 0;
}
 
F

Frederick Gotham

SkyBlue posted:
char *one;
char *two;


Both of these variables are pointers. They are a non-const pointer to a
non-const char.

A pointer variable is just like any other variable -- it consumes memory
and stores data by arranging bits in a particular pattern.

The purpose of an int is to store an integer.
The purpose of a double is to store a floating-point number.
The purpose of a pointer is to store a memory address.

What is a memory address? 10? 5737? 2972529? I suppose we can presume it's
some sort of number, no?

On the particular system you're working with, a pointer variable might
consume 32 bits in memory; therefore, to store the memory address 2972529,
the pointer might store the following bit-pattern in memory:

00000000001011010101101101110001

Now, I'm going to shift the attention away from pointers for the moment,
and tell you a little about "automatic storage variables". When you define
a variable within a function, it's called an automatic storage variable
(unless of course you define it as "static" -- in which case it would be a
static duration variable.). If an automatic variable is not assigned a
value (as in your code snippet), then its value is indeterminant -- it
contains white noise, a bit-pattern left over from when that piece of
memory was last used. You have defined two automatic variables, but you
have not initialised them; therefore, they contain garbage, a random
number, a random memory address.

You then invoke "fgets" and provide it with these two random memory
addresses. In order to read or write memory, you must obliged to do so, you
must be permitted to do so. How do we gain permission to read and write a
certain block of memory... ? By allocating that memory for our own use, of
course. There's a function in the Standard Library called "malloc"; when
calling it, you specify how many bytes of memory you wish to allocate, and
the function returns the address of the newly allocated block of memory. So
let's store a valid address in our char pointers:

char *const one = malloc(512);
char *const two = malloc(512);

The values stored in "one" and "two" are not random -- they are the
addresses of dynamically allocated blocks of memory which are yours to
manipulate however you please.

Don't forget to then free the memory by passing the memory addresses to
"free":

free(one);
free(two);

I simplified a lot of the above (e.g. I haven't talked about trapping, or
the invocation of undefined behaviour by accessing an un-initialised
variable), but hopefully you get the idea.
 
M

Martin Ambuhl

SkyBlue said:
Hi, can someone explain why the following simple C code segfaulted?
I've stared it for 30mins but couldn't find the problem. Thx in advance

#include <stdio.h>

int main() {

char *one;
char *two;

fgets(one, 200, stdin);
^^^
You have allocated no memory for one to point to. How should I spend
the other 29:59?
 
J

Joe Wright

Frederick said:
SkyBlue posted:



Both of these variables are pointers. They are a non-const pointer to a
non-const char.

A pointer variable is just like any other variable -- it consumes memory
and stores data by arranging bits in a particular pattern.

The purpose of an int is to store an integer.
The purpose of a double is to store a floating-point number.
The purpose of a pointer is to store a memory address.

What is a memory address? 10? 5737? 2972529? I suppose we can presume it's
some sort of number, no?

On the particular system you're working with, a pointer variable might
consume 32 bits in memory; therefore, to store the memory address 2972529,
the pointer might store the following bit-pattern in memory:

00000000001011010101101101110001

Now, I'm going to shift the attention away from pointers for the moment,
and tell you a little about "automatic storage variables". When you define
a variable within a function, it's called an automatic storage variable
(unless of course you define it as "static" -- in which case it would be a
static duration variable.). If an automatic variable is not assigned a
value (as in your code snippet), then its value is indeterminant -- it
contains white noise, a bit-pattern left over from when that piece of
memory was last used. You have defined two automatic variables, but you
have not initialised them; therefore, they contain garbage, a random
number, a random memory address.

You then invoke "fgets" and provide it with these two random memory
addresses. In order to read or write memory, you must obliged to do so, you
must be permitted to do so. How do we gain permission to read and write a
certain block of memory... ? By allocating that memory for our own use, of
course. There's a function in the Standard Library called "malloc"; when
calling it, you specify how many bytes of memory you wish to allocate, and
the function returns the address of the newly allocated block of memory. So
let's store a valid address in our char pointers:

char *const one = malloc(512);
char *const two = malloc(512);

The values stored in "one" and "two" are not random -- they are the
addresses of dynamically allocated blocks of memory which are yours to
manipulate however you please.
Shouldn't you test whether malloc was successful?
Don't forget to then free the memory by passing the memory addresses to
"free":

free(one);
free(two);

I simplified a lot of the above (e.g. I haven't talked about trapping, or
the invocation of undefined behaviour by accessing an un-initialised
variable), but hopefully you get the idea.

The point of free() is to allow the re-use of allocated memory within
the program. To free() allocated memory just prior to program
termination is harmless but useless. The OS will reclaim all allocated
memory when your program terminates.
 
M

Martin Ambuhl

Joe said:
The point of free() is to allow the re-use of allocated memory within
the program. To free() allocated memory just prior to program
termination is harmless but useless. The OS will reclaim all allocated
memory when your program terminates.

You may believe this, but that doesn't make it so. Your OS may behave
this way, but that doesn't make it true elsewhere. Unless you can show
where the standard for C requires this, keep your non-portable,
system-specific opinions to yourself. Your flat claim is patently false.
 
S

Spiros Bousbouras

Martin said:
You may believe this, but that doesn't make it so. Your OS may behave
this way, but that doesn't make it true elsewhere. Unless you can show
where the standard for C requires this, keep your non-portable,
system-specific opinions to yourself. Your flat claim is patently false.

How do you know that the claim is false ? Do you have
an example of an operating system which doesn't
reclaim allocated memory ?
 
F

Frederick Gotham

Spiros Bousbouras posted:
How do you know that the claim is false ? Do you have
an example of an operating system which doesn't
reclaim allocated memory ?


That's a bad argument to put across. I've never seen a C implementation which
has 13-Bit char's, 17-Bit int's, and uses One's Complement -- but I'll shun
any portable code which doesn't make allowances for it.

I haven't got the C Standard, so I don't know what it says about requiring to
"free" all memory.
 
R

Richard Heathfield

Joe Wright said:

The point of free() is to allow the re-use of allocated memory within
the program. To free() allocated memory just prior to program
termination is harmless but useless. The OS will reclaim all allocated
memory when your program terminates.

That kind of thinking costs money, when main() becomes foo(), and foo() is
called in a loop. Fortunately, money is conserved, and the maintenance
programmer's family gets buns for tea.
 
K

Keith Thompson

Martin Ambuhl said:
You may believe this, but that doesn't make it so. Your OS may behave
this way, but that doesn't make it true elsewhere. Unless you can
show where the standard for C requires this, keep your non-portable,
system-specific opinions to yourself. Your flat claim is patently
false.

Are you assuming that memory that has been free()d *will* be reclaimed
by the operating system? If so, what is your basis for that
assumption?
 
K

Keith Thompson

Frederick Gotham said:
Spiros Bousbouras posted:

That's a bad argument to put across. I've never seen a C
implementation which has 13-Bit char's, 17-Bit int's, and uses One's
Complement -- but I'll shun any portable code which doesn't make
allowances for it.

I agree with the general point, but if CHAR_BIT is 13, int must be at
least 26 bits (though it could have 9 padding bits).
I haven't got the C Standard, so I don't know what it says about
requiring to "free" all memory.

Why don't you have the C standard? Just grab a copy of n1124.pdf.
 
F

Frederick Gotham

Keith Thompson posted:
I agree with the general point, but if CHAR_BIT is 13, int must be at
least 26 bits (though it could have 9 padding bits).


Yes, 26 object representation bits consisting of 17 value representation bits
and 9 padding bits. ; )

Why don't you have the C standard? Just grab a copy of n1124.pdf.


I didn't realise it was free... I just downloaded it now!
 
K

Keith Thompson

Frederick Gotham said:
Spiros Bousbouras posted:


That's a bad argument to put across. I've never seen a C
implementation which has 13-Bit char's, 17-Bit int's, and uses One's
Complement -- but I'll shun any portable code which doesn't make
allowances for it.

Well, any code that doesn't make allowances for that kind of thing
isn't portable.

On the other hand, not all code has to be portable. If you have no
need to run your code on a platform with CHAR_BIT>8, *and* if there's
a real advantage in assuming that CHAR_BIT==8, then I see no great
problem in writing code that depends on that assumption. (For
example, I think POSIX guarantees CHAR_BIT==8, and a few other things;
if I'm using POSIX-specific library functions, there's not much point
in allowing for 9-bit chars.)

But I would advocate making any such assumptions explicit, so if
someone tries to compile the code on some exotic system that doesn't
satisfy the assumptions, the error is caught as early and as cleanly
as possible.
 
M

Martin Ambuhl

Keith said:
Are you assuming that memory that has been free()d *will* be reclaimed
by the operating system?

There is nothing in my post from which you can extrapolate such an
assumption.
If so, what is your basis for that
assumption?

What is your basis for trying to force assumptions onto me and then
pretending I have some obligation to justify your claimed assumption.

Please try a little honesty.
 
S

Spiros Bousbouras

Frederick said:
Spiros Bousbouras posted:



That's a bad argument to put across. I've never seen a C implementation which
has 13-Bit char's, 17-Bit int's, and uses One's Complement -- but I'll shun
any portable code which doesn't make allowances for it.

But I wasn't putting any argument across nor did I
need to because it wasn't me who was advocating an
opinion. It was Martin Ambuhl who wrote that the
claim (that every operating system will reclaim allocated
memory after the programme finishes) was false so he
needs to come up with the arguments or supporting
evidence.

Having said that I do consider it improbable that such an
operating system exists simply on the basis that it would
be so bad that noone would use it plus it would probably be
easy to fix things so that it did reclaim allocated memory
after the programme finished.

" but I'll shun any portable code which doesn't make allowances for
it."

Does your code make provisions for every occurence allowed
by the standard no matter how improbable ? Do you for
example check the return value of printf in your code ? I doubt
it. Do you consider more probable that some operating system
won't reclaim memory than that printf will return a negative
value ? I don't.
 
K

Keith Thompson

Martin Ambuhl said:
There is nothing in my post from which you can extrapolate such an
assumption.

I didn't say there was. That's why I asked the question.
What is your basis for trying to force assumptions onto me and then
pretending I have some obligation to justify your claimed assumption.

I have not done so.
Please try a little honesty.

Please try a little reading comprehension. I asked a question.
Rather than answering it, you chose to make assumptions about what was
behind it.

If you're not assuming that memory that has been free()d will be
reclaimed by the OS, then the answer to my first question would be a
simple no, and the second question, as I expicitly acknowledged, would
not be applicable.

Was your suggestion that I "try a little honesty" meant to imply that
I've been dishonest? If so, please explain. (And please read this
paragraph more carefully than you seem to have read my previous
questions.)
 
M

Martin Ambuhl

Keith said:
Please try a little reading comprehension. I asked a question.
Rather than answering it, you chose to make assumptions about what was
behind it.

You asked a question that imputed to me an assumption. It was an
assumption I never made, about an issue which I never speculated on.
You made the assumption out of your own imagination: you answer it. You
have repeatedly pulled this puerile parlor trick of imputing to people
assumptions they never made and then demanding answers, hiding behind
the obvious facade of "I just asked a question." This may impress the
other kiddies at your day care center, but honest adults don't do this.
Go back to your sandbox.
 
C

CBFalconer

Richard said:
Joe Wright said:



That kind of thinking costs money, when main() becomes foo(), and
foo() is called in a loop. Fortunately, money is conserved, and
the maintenance programmer's family gets buns for tea.

However there exist systems in which free is O(n), where n is the
count of allocations made. This makes freeing everything on exit
O(n*n), and can be a real drag.

This was the motivation for my writing nmalloc for DJGPP, see:

<http://cbfalconer.home.att.net/download/>

The problem arose when validating my hashlib package. Closing the
database requires freeing all the associated storage. The O(n*n)
effect showed up dramatically when there were a few hundred
thousand items involved, and manifested itself as a heavy delay on
program exit. I didn't check every system in existance, but found
that the problem existed on DJGPP, LCC-WIN32, and VC. The problem
arises in combining freed areas.

nmalloc makes free O(1), and thus the complete free becomes O(n).
No matter how fast the underlying system is, O(n*n) response will
catch you sooner or later.

The point of all this is that avoiding the final free action in a
program can avoid those delays. The test suite for hashlib enables
either action.

A further point is that this demonstrates the efficacy of open
source. I could fix DJGPP. I couldn't fix the others.
 
K

Keith Thompson

Martin Ambuhl said:
You asked a question that imputed to me an assumption. It was an
assumption I never made, about an issue which I never speculated
on. You made the assumption out of your own imagination: you answer
it. You have repeatedly pulled this puerile parlor trick of imputing
to people assumptions they never made and then demanding answers,
hiding behind the obvious facade of "I just asked a question." This
may impress the other kiddies at your day care center, but honest
adults don't do this. Go back to your sandbox.

Bye.
 

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,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top