printf() and character arrays

E

Eirik

Look at this code:

#include <stdio.h>

int main(void) {

char name[50];
printf("What is your name?\n");
fgets(name, sizeof(name), stdin);
printf("Your name is %s.\n", name);

return 0;

}

I get the comma on a separate line. I know why, it is
because of the '\n' at the end of "name"(that's at least what
I think, but how can I remove it?

I have another question: How do real programmers in real
programs deal with memory allocation? Previously, when
I have asked questions, people have called my programs
'toy applications', which they are, because
they don't have any memory allocation. How does a
programmer that is working on a big application with
many variables do?
 
E

Eric Sosman

Eirik said:
Look at this code:

#include <stdio.h>

int main(void) {

char name[50];
printf("What is your name?\n");
fgets(name, sizeof(name), stdin);
printf("Your name is %s.\n", name);

return 0;

}

I get the comma on a separate line.

Comma? What comma? Am I going blind?
I know why, it is
because of the '\n' at the end of "name"(that's at least what
I think, but how can I remove it?

Search for it and replace it with '\0'. Here's one
way:

char *p;
...
p = strchr(name, '\n');
if (p != NULL)
*p = '\0';
I have another question: How do real programmers in real
programs deal with memory allocation? Previously, when
I have asked questions, people have called my programs
'toy applications', which they are, because
they don't have any memory allocation. How does a
programmer that is working on a big application with
many variables do?

"It depends."

Some applications just call malloc() and friends as
needed. Others wrap fancier application-specific memory
managers around them. Still others don't use malloc()
and friends at all, but substitute their own complete
memory management packages (of course, when they do this
they have ventured outside the territory mapped by the
Standard).

The biggest application I personally have written code
for was a relatively modest affair of about three million
source lines, ~80% C and ~20% Lisp. It used a hodgepodge
of different allocators (in entirely non-Standard fashion):

- malloc() and friends,

- system-specific APIs like sbrk() and mmap(),

- a special allocator for pools of related fixed-
size memory blocks,

- another allocator for pools of variable-size blocks,

- replacements for malloc() and friends, built atop
the variable-sized allocator,

- the memory management of the Lisp interpreter, built
atop all of the above (and, of course, including
garbage collection),

- idiosyncratic memory managers in individual subsystems,
built atop all of the above,

- ... and probably a few more I've forgotten or was never
aware of in the first place.

I'm not saying that this sort of a melange is appropriate
for all "big" applications. However, it's my impression that
many large programs chafe at the restrictions that come along
with the simplicity of malloc() and friends, and find themselves
building fancier (and less simple) memory managers to make
life easier for them. Sometimes these fancier packages use
malloc() and friends as their underpinnings, and sometimes
they don't.
 
S

Stig Brautaset

Eirik said:
Look at this code:

#include <stdio.h>

int main(void) {

char name[50];
printf("What is your name?\n");
fgets(name, sizeof(name), stdin);

/* this removes the last character in the array (which will be the \n
* unless you typed in too many characters to fit in the array). It
* would be better to test if the last character is a newline.
*/
name[strlen(name) - 1] = '\0';
printf("Your name is %s.\n", name);

return 0;

}

I get the comma on a separate line. I know why, it is
because of the '\n' at the end of "name"(that's at least what
I think, but how can I remove it?

Stig
 
N

nrk

Eric said:
Eirik said:
Look at this code:

#include <stdio.h>

int main(void) {

char name[50];
printf("What is your name?\n");
fgets(name, sizeof(name), stdin);
printf("Your name is %s.\n", name);

return 0;

}

I get the comma on a separate line.

Comma? What comma? Am I going blind?

Probably a daft European thing, where they say "," when they obviously mean
"." :)

<snip>

-nrk.
 
K

Keith Thompson

Stig Brautaset said:
/* this removes the last character in the array (which will be the \n
* unless you typed in too many characters to fit in the array). It
* would be better to test if the last character is a newline.
*/
name[strlen(name) - 1] = '\0';
[...]

It would be easier, or at least shorter, to provide a correct solution
than to explain why this one isn't quite correct.
 
J

Joona I Palaste

Keith Thompson said:
Stig Brautaset said:
/* this removes the last character in the array (which will be the \n
* unless you typed in too many characters to fit in the array). It
* would be better to test if the last character is a newline.
*/
name[strlen(name) - 1] = '\0'; [...]

It would be easier, or at least shorter, to provide a correct solution
than to explain why this one isn't quite correct.

How about this, then?
name[strlen(name) ? strlen(name)-1 : 0] = '\0';
 
B

Ben Pfaff

Joona I Palaste said:
Keith Thompson said:
Stig Brautaset said:
/* this removes the last character in the array (which will be the \n
* unless you typed in too many characters to fit in the array). It
* would be better to test if the last character is a newline.
*/
name[strlen(name) - 1] = '\0'; [...]

It would be easier, or at least shorter, to provide a correct solution
than to explain why this one isn't quite correct.

How about this, then?
name[strlen(name) ? strlen(name)-1 : 0] = '\0';

I'd prefer this for removing the last character in a string in general:
if (string[0] != '\0')
name[strlen (string) - 1] = '\0';
or even:
if (string[0] != '\0')
strchr (string, '\0')[-1] = '\0';
though that may be too obscure. But for this particular case:
p = strchr (string, '\n');
if (p != NULL)
*p = '\0';
 
A

Alex

Joona I Palaste said:
Keith Thompson said:
Stig Brautaset said:
/* this removes the last character in the array (which will be the \n
* unless you typed in too many characters to fit in the array). It
* would be better to test if the last character is a newline.
*/
name[strlen(name) - 1] = '\0';
[...]
It would be easier, or at least shorter, to provide a correct solution
than to explain why this one isn't quite correct.
How about this, then?
name[strlen(name) ? strlen(name)-1 : 0] = '\0';

Huh?

This tests if the string is longer than 0, and either removes
the last character or resets the terminating NUL. What does
this have to do with anything?

What you do need to do is make sure that the last character
is '\n' and, if it is, truncate it. If it is not a newline,
then the overflow should be handled intelligently.

Alex
 
J

Joona I Palaste

Alex said:
Joona I Palaste said:
Keith Thompson said:
[..]
/* this removes the last character in the array (which will be the \n
* unless you typed in too many characters to fit in the array). It
* would be better to test if the last character is a newline.
*/
name[strlen(name) - 1] = '\0';
[...]
It would be easier, or at least shorter, to provide a correct solution
than to explain why this one isn't quite correct.
How about this, then?
name[strlen(name) ? strlen(name)-1 : 0] = '\0';

This tests if the string is longer than 0, and either removes
the last character or resets the terminating NUL. What does
this have to do with anything?

It has to do with my not reading the thread. There *IS* an unhandled
issue with the original code - if the string happens to be "", i.e. a
string consisting of just the terminating NUL, then the original code
causes undefined behaviour, while mine doesn't.
But that was most likely not the issue Keith was thinking about. Now
that I think of it, the possibility of the string being "" would never
arise if we use the code in the way it's presented in this thread.
 
A

Alex

Joona I Palaste said:
Alex said:
Joona I Palaste said:
Keith Thompson <[email protected]> scribbled the following:
[..]
/* this removes the last character in the array (which will be the \n
* unless you typed in too many characters to fit in the array). It
* would be better to test if the last character is a newline.
*/
name[strlen(name) - 1] = '\0';
[...]
It would be easier, or at least shorter, to provide a correct solution
than to explain why this one isn't quite correct.
How about this, then?
name[strlen(name) ? strlen(name)-1 : 0] = '\0';
Huh?
This tests if the string is longer than 0, and either removes
the last character or resets the terminating NUL. What does
this have to do with anything?
It has to do with my not reading the thread. There *IS* an unhandled
issue with the original code - if the string happens to be "", i.e. a
string consisting of just the terminating NUL, then the original code
causes undefined behaviour, while mine doesn't.

This is generally a good point, but not in the context of fgets.

If fgets does not return NULL and the length argument is larger
than 0, then the string may never end up being "".

Alex
 
C

CBFalconer

Joona said:
Keith Thompson said:
Stig Brautaset said:
/* this removes the last character in the array (which will be the \n
* unless you typed in too many characters to fit in the array). It
* would be better to test if the last character is a newline.
*/
name[strlen(name) - 1] = '\0'; [...]

It would be easier, or at least shorter, to provide a correct
solution than to explain why this one isn't quite correct.

How about this, then?
name[strlen(name) ? strlen(name)-1 : 0] = '\0';

I thought the idea was to remove a (possible) terminating '\n'.

if (p = strchr(name, '\n') *p = '\0';

with suitable declarations.
 
J

John Bode

Eirik said:
Look at this code:

#include <stdio.h>

int main(void) {

char name[50];
printf("What is your name?\n");
fgets(name, sizeof(name), stdin);
printf("Your name is %s.\n", name);

return 0;

}

I get the comma on a separate line. I know why, it is
because of the '\n' at the end of "name"(that's at least what
I think, but how can I remove it?

char *p = strrchr (name, '\n');
if (p)
*p = 0;

strrchr() returns a pointer to the last occurrence of the newline
character in name; if the pointer is not NULL, set the value at that
location to 0. If strrchr() returns NULL, that means the newline was
not found in name. This could mean that someone typed in a name
longer than you were expecting, and that there are still characters in
the input buffer. Or it could mean that someone terminated input by
typing ^Z or ^D or something.
I have another question: How do real programmers in real
programs deal with memory allocation? Previously, when
I have asked questions, people have called my programs
'toy applications', which they are, because
they don't have any memory allocation. How does a
programmer that is working on a big application with
many variables do?

It depends on the situation. Some big applications can get by with
statically allocated memory, some get by with a mix of static and
dynamic allocation, some require extensive dynamic allocation. I
worked on a sonar simulator for the Navy (a big app, at least as far
as LOC were concerned), and it used static buffers almost exclusively.
Another project was an output manager that routed jobs throughout an
enterprise, and that required extensive dynamic memory management (job
queues could grow and shrink a great deal over the course of a day).

Right now I'm working on a C4I system for the military, and it falls
into the roughly half-and-half camp. The configuration and user
interface software rely mostly on dynamic memory management, the data
forwarding and track management software use mostly static memory.
 
J

Joe Wright

CBFalconer said:
Keith Thompson said:
[..]
/* this removes the last character in the array (which will be the \n
* unless you typed in too many characters to fit in the array). It
* would be better to test if the last character is a newline.
*/
name[strlen(name) - 1] = '\0';
[...]
It would be easier, or at least shorter, to provide a correct
solution than to explain why this one isn't quite correct.

How about this, then?
name[strlen(name) ? strlen(name)-1 : 0] = '\0';

I thought the idea was to remove a (possible) terminating '\n'.

if (p = strchr(name, '\n') *p = '\0';

with suitable declarations.

Or, just maybe another paren for balance..

if (p = strchr(name, '\n')) *p = '\0';

...and if you want to keep gcc quiet, a couple more..

if ((p = strchr(name, '\n'))) *p = '\0';
 
J

Jared Dykstra

Eirik said:
Look at this code:

#include <stdio.h>

int main(void) {

char name[50];
printf("What is your name?\n");
fgets(name, sizeof(name), stdin);
printf("Your name is %s.\n", name);

return 0;

}

I get the comma on a separate line. I know why, it is
because of the '\n' at the end of "name"(that's at least what
I think, but how can I remove it?

I have another question: How do real programmers in real
programs deal with memory allocation? Previously, when
I have asked questions, people have called my programs
'toy applications', which they are, because
they don't have any memory allocation. How does a
programmer that is working on a big application with
many variables do?


Memory Management completely depends on the application, development
timelines & requirements, how the application is to be used, and
hardware available.

Dynamic memory allocation is surprisingly slow because a lot of
overhead is spent managing the heap. Some operating systems (such as
Palm OS) will even attempt to defragement the heap if a large enough
chunk is not available. Allocating and releasing small pieces
unnecessarly can also lead to fragmentation problems, particularly on
embedded devices with very little available RAM.

On the other hand, static allocation has it's own drawbacks. #1, at
best the memory is tied up as long as it is in scope, but more likely
is in use as long as the program is running. With dynamic allocation,
you can return the memory to the heap as soon as you know it is no
longer being used.

Finally, to skirt the issue of memory management all together, you may
wish to read up on garbage collectors--the most popular being part of
any Java Virtual Machine; however, that is for a separate group.
There are garbage collectors for C too, but there are good reasons
you'll be hard pressed to find a C/C++ program that uses 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

No members online now.

Forum statistics

Threads
474,122
Messages
2,570,717
Members
47,283
Latest member
VonnieEwan

Latest Threads

Top