744 lines
34 KiB
HTML
744 lines
34 KiB
HTML
<!--startcut ==============================================-->
|
|
<!-- *** BEGIN HTML header *** -->
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
|
<HTML><HEAD>
|
|
<title>The Standard C Library for Linux, part 7: String Handling LG #76</title>
|
|
</HEAD>
|
|
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
|
|
ALINK="#FF0000">
|
|
<!-- *** END HTML header *** -->
|
|
|
|
<CENTER>
|
|
<A HREF="http://www.linuxgazette.com/">
|
|
<IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.png"
|
|
WIDTH="600" HEIGHT="124" border="0"></A>
|
|
<BR>
|
|
|
|
<!-- *** BEGIN navbar *** -->
|
|
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="qubism.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue76/rogers.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="spiel.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
|
|
<!-- *** END navbar *** -->
|
|
<P>
|
|
</CENTER>
|
|
|
|
<!--endcut ============================================================-->
|
|
|
|
<H4 ALIGN="center">
|
|
"Linux Gazette...<I>making Linux just a little more fun!</I>"
|
|
</H4>
|
|
|
|
<P> <HR> <P>
|
|
<!--===================================================================-->
|
|
|
|
<center>
|
|
<H1><font color="maroon">The Standard C Library for Linux, part 7: String Handling</font></H1>
|
|
<H4>By <a href="mailto:buckrogers@users.sourceforge.net">James M Rogers</a></H4>
|
|
</center>
|
|
<P> <HR> <P>
|
|
|
|
<!-- END header -->
|
|
|
|
|
|
|
|
|
|
<EM>I finally have time (after a few years) to give back a little more to
|
|
the Linux community with the next in my series of articles on the Standard
|
|
C Library. I hope that you enjoy.</EM> </p>
|
|
|
|
<p>The <A HREF="../issue41/rogers.html">last article</A> was on <assert.h>
|
|
diagnostics for programmers.
|
|
This article is on <string.h> string handling. C is not
|
|
much better at handling strings than machine code, so machine language programmers
|
|
will feel quite at home in this section. There are many limitations
|
|
and problems with string.h that will be addressed in the appropriate function
|
|
descriptions. </p>
|
|
|
|
<p>I am assuming a knowledge of C programming on the part of the reader.
|
|
There is no guarantee of accuracy in any of this information nor suitability
|
|
for any purpose. </p>
|
|
|
|
<p>The example is <a href="misc/rogers/rogers_example07.c">
|
|
rogers_example07.c</a> . This is a basic example that will demonstrate
|
|
each of the string functions. If you compile it and run it you will
|
|
be able to see the output. Compare the output to the code and enjoy.
|
|
</p>
|
|
|
|
<p>As always, if you see an error in my documentation please tell me and I
|
|
will correct myself in a later document. See corrections at end of
|
|
the document to review corrections to the previous articles. </p>
|
|
|
|
<p><b>WARNING:</b> Copying strings in C is the most dangerous part of
|
|
programming in C. C itself doesn't perform bounds checking, so it is
|
|
very easy to overwrite the end of a string and actually overwrite other variables
|
|
or even to crash the program. Crackers use this weakness in C and inexpert
|
|
coding practices to perform controlled overflows to force programs into giving
|
|
them a shell to the account that the program is running under. This
|
|
is usually root for most servers. </p>
|
|
|
|
<p>C doesn't really have strings. I know that is a strange thing to
|
|
say in a document talking about string handling in C, but it is true.
|
|
What C does have is an array of characters. To make space for a string
|
|
you can ask the compiler to reserve room for that string. The most
|
|
common way is with a simple character array: </p>
|
|
|
|
<p><tt>char string[17];</tt> </p>
|
|
|
|
<p>This reserves room for 16 characters and an end-of-string marker. </p>
|
|
|
|
<p><tt>strcpy ( string, "This is a string" );</tt> </p>
|
|
|
|
<p>Will work to copy the static string "This is a string" into the space that
|
|
we allocated. The static string is composed of 16 characters followed
|
|
by the ASCII nil character. So there is plenty of room in the variable
|
|
called string to hold the static string. Nil is typically represented
|
|
with the number zero or with the character '\0' or with the character '\000'.
|
|
</p>
|
|
|
|
<p>Surprisingly the following will sometimes work as well, even though there
|
|
are more then 17 characters copied into the char array: </p>
|
|
|
|
<p><tt>strcpy ( string, "This is a long string" );</tt> </p>
|
|
|
|
<p>There is never any bounds checking when you are copying strings.
|
|
So even though you went past the end of string and wrote to memory in an
|
|
unexpected way, most of the time you can get away with it. Of course
|
|
your program can also unexpectedly crash at anytime as well, sometimes in
|
|
a place far away from the place where you made your error. Crackers
|
|
can get a shell from the computer by overwriting the end of a buffer in such
|
|
a way that the program executes a shell. This is one of the reasons
|
|
that you should really not use strcpy. Use strncpy instead: </p>
|
|
|
|
<p><tt>#define MAX_STRING_LENGTH 17</tt> <br>
|
|
<tt>char string[MAX_STRING_LENGTH];</tt> <br>
|
|
<tt>strncpy ( string, "This is a long string", MAX_STRING_LENGTH );</tt>
|
|
<br>
|
|
<tt>string[MAX_STRING_LENGTH-1] = '\000';</tt> </p>
|
|
|
|
<p>The reason that I used a macro for the string length is that I am using
|
|
this length in many places in my program, if I ever decide to change the
|
|
size of the variable string I would have to find everywhere where I used
|
|
the number 17 and fix each one. Sometimes you may use the same number
|
|
in different places to mean different things. So even if you only use
|
|
a literal number in a few places using a macro can make the meaning of that
|
|
number really stand out and it makes it trivial to change the size of the
|
|
string buffer in this case. </p>
|
|
|
|
<p>The reason that I put the last line there is that if the literal string
|
|
is longer than the string that we are copying into then the end-of-string
|
|
marker isn't put into place. If you don't set the final character
|
|
to null, most of the time you will be fine, but every once in a while your
|
|
program will crash and you will wonder why. </p>
|
|
|
|
<p>There is also a third way to define a string and that is with malloc, realloc
|
|
and calloc. These functions work by requesting the memory that you
|
|
need at runtime. This is the most complicated but also the most flexible
|
|
and powerful. </p>
|
|
|
|
<p><tt>#define STATIC_STRING "This is a long string that will be copied into
|
|
a location during runtime"</tt> </p>
|
|
|
|
<p><tt>char *string;</tt> <br>
|
|
<tt>int string_length;</tt> </p>
|
|
|
|
<p><tt>string_length = strlen(STATIC_STRING);</tt> </p>
|
|
|
|
<p><tt>if (!(string = (char *) malloc ( string_length ))){</tt> <br>
|
|
<tt> /* no memory left, die */</tt> <br>
|
|
<tt> exit (1);</tt> <br>
|
|
<tt>}</tt> </p>
|
|
|
|
<p><tt>strncpy( string, STATIC_STRING, string_length);</tt> <br>
|
|
<tt>string[string_length] = '\000';</tt> </p>
|
|
|
|
<p><tt>/* do something with the string */</tt> </p>
|
|
|
|
<p><tt>free(string);</tt> </p>
|
|
|
|
<p> </p>
|
|
One of the dangers of this method is that you have to clean up after
|
|
yourself, using the free function. If you don't free everything when
|
|
you are done with then you will be leaking memory and eventually your program
|
|
will crash.<br>
|
|
|
|
<hr noshade>
|
|
<p>The <string.h> library has numerous problems. </p>
|
|
|
|
<p>The biggest problem is that the library was never designed to be complete
|
|
and consistent. <string.h> really is a collection of functions
|
|
written by various people, assembled into a library and given to the world.
|
|
And now we are stuck with it. </p>
|
|
|
|
<p>Most of the functions can return a NULL or a pointer to a string.
|
|
If a function <EM>can</EM> return a NULL, you should always check the return
|
|
value after calling it, and take appropriate action if it is NULL. If you
|
|
attempt to treat a NULL return value as a pointer to a string, you will quickly
|
|
crash your program. </p>
|
|
|
|
<p> </p>
|
|
|
|
<hr noshade>
|
|
<p>I have arbitrarily grouped the functions into sections according to task,
|
|
to show the slight differences between similar functions. One could also
|
|
group by string functions vs memory functions, but that seemed less useful.
|
|
</p>
|
|
|
|
<p> </p>
|
|
|
|
<hr noshade>
|
|
<p><b><font size="+1">Copying</font></b> </p>
|
|
|
|
<ul>
|
|
<tt>#include <string.h></tt>
|
|
<p><tt>void *memcpy(void *dest, const void *src, size_t n);</tt> <br>
|
|
<tt>void *memmove(void *dest, const void *src, size_t n);</tt> <br>
|
|
<tt>char *strncpy(char *dest, const char *src, size_t n);</tt> <br>
|
|
<tt>char *strcpy(char *dest, const char *src);</tt> <br>
|
|
</p>
|
|
|
|
</ul>
|
|
<tt>void *dest</tt> is a pointer to the array which will receive the
|
|
copy. <br>
|
|
<tt>char *dest</tt> is a pointer to the string which will receive the
|
|
copy. <br>
|
|
<tt>const void *src</tt> is a pointer to the array from which the
|
|
copy will be made. <br>
|
|
<tt>const char *src</tt> is a pointer to the string from which the copy
|
|
will be made. <br>
|
|
<tt>size_t n </tt>is the number of characters to be copied.
|
|
<p>These functions all return a pointer to dest. Which is strange, because
|
|
you already have a pointer to dest. </p>
|
|
|
|
<p><b>memcpy</b> copies n characters from the location pointed at by src to
|
|
the location pointed at by dest. Don't copy areas that overlap or your
|
|
program will crash. </p>
|
|
|
|
<p><b>memmove</b> also copies n characters from the location pointed at by
|
|
src to the location pointed at by dest. But it first copies the characters
|
|
to a temporary location then into the final location, so this is the function
|
|
to use if you are copying overlapping areas of memory. </p>
|
|
|
|
<p><b>strncpy</b> copies no more than n characters from the location pointed
|
|
at by src to the location pointed at by dest. This function will stop
|
|
at the first null character, which may be at any location less than or equal
|
|
to n. If n characters are copied and no null is found, no null is written.
|
|
This is a great way to leave the end of a string open. You should
|
|
always explictly write zero to the end of the string. </p>
|
|
|
|
<p><b>strcpy</b> copies the string pointed at by src to the location pointed
|
|
at by dest, including the ending null character. <b>Warning! Never
|
|
use this function for data that comes from the real world !!! </b>
|
|
The biggest danger of using this function is that if there is no
|
|
null character you will happily go copying through memory until you randomly
|
|
find a null or you access memory that doesn't belong to your process and
|
|
the process is killed with a SEGV (segfault) signal. Programs can capture this signal
|
|
and shutdown, but at this point you are so hosed that it is best just to
|
|
let the program core dump. </p>
|
|
|
|
<p>I have already given a few examples of how to use strcpy and strncpy.
|
|
memcpy and memmove are used exactly like strncpy, but they can copy arbitrary
|
|
blocks of bytes, not just strings. </p>
|
|
|
|
<p> </p>
|
|
|
|
<hr noshade>
|
|
<p><b><font size="+1">Concatenation</font></b> </p>
|
|
|
|
<ul>
|
|
<tt>#include <string.h></tt>
|
|
<p><tt>char *strcat(char *dest, const char *src);</tt> <br>
|
|
<tt>char *strncat(char *dest, const char *src, size_t n);</tt></p>
|
|
|
|
</ul>
|
|
<tt>char *dest </tt> is a pointer to the string which will receive
|
|
the copy. <br>
|
|
<tt>const char *src</tt> is a pointer to the string from which
|
|
the copy will be made. <br>
|
|
<tt>size_t n</tt> is the number of characters to be copied. <br>
|
|
|
|
<p><b>strcat</b> appends the source string, including the final '\0', onto
|
|
the end of the destination string. It overwrites the trailing '\0' on the
|
|
end of the destination string. </p>
|
|
|
|
<p><b>strncat</b> does the same, except it will only copy at most n characters
|
|
from destination and it will append a '\0'. </p>
|
|
|
|
<p>Both <b>strcat </b>and <b>strncat</b> return a pointer to the destination
|
|
string. Again, there is no bounds checking on the resulting string,
|
|
so make sure that the string you create isn't too long to fit in the memory
|
|
you have allocated for it. </p>
|
|
|
|
<p> </p>
|
|
|
|
<hr noshade>
|
|
<p><b><font size="+1">Comparison</font></b> </p>
|
|
|
|
<ul>
|
|
<tt>#include <string.h></tt>
|
|
<p><tt>int memcmp(const void *s1, const void *s2, size_t n);</tt> <br>
|
|
<tt>int strcmp(const char *s1, const char *s2);</tt> <br>
|
|
<tt>int strncmp(const char *s1, const char *s2, size_t n);</tt> <br>
|
|
<tt>int strcoll(const char *s1, const char *s2);</tt> <br>
|
|
<tt>size_t strxfrm(const char *s1, const char *s2, size_t n);</tt></p>
|
|
|
|
</ul>
|
|
<tt>const char *s1</tt> is a pointer to the first string. <br>
|
|
<tt>const void *s1</tt> is a pointer to the first memory array.
|
|
<br>
|
|
<tt>const char *s2</tt> is a pointer to the second string. <br>
|
|
<tt>const void *s2</tt> is a pointer to the second memory array.
|
|
<br>
|
|
<tt>size_t n</tt> is the number of characters to be copied.
|
|
|
|
<p><b>memcmp</b> compares the number of bytes given by n. If s1
|
|
is less than s2, return a value less than zero. If s1 is equal to s2,
|
|
return zero. If s1 is greater than s2, return a value greater than
|
|
zero. The comparison is based on the byte values of the ASCII characters
|
|
in the memory array. </p>
|
|
|
|
<p><b>strcmp</b> compares the two strings s1 and s2. A string is a
|
|
null terminated array of characters. If s1 is less than s2, return
|
|
a value less than zero. If s1 is equal to s2, return zero.
|
|
If s1 is greater than s2, return a value greater than zero. The comparison
|
|
is based on the byte values of the ASCII characters in the two strings.
|
|
</p>
|
|
|
|
<p><b>strncmp</b> is very similar to memcmp, except that it compares the two
|
|
strings, up to the length given by n. If a string is shorter than n,
|
|
than the memory locations following n are not compared. If s1
|
|
is less than s2, return a value less than zero. If s1 is equal to s2,
|
|
return zero. If s1 is greater than s2, return a value greater than
|
|
zero. </p>
|
|
|
|
<p><b>strcoll</b> compares the two strings s1 and s2. If
|
|
s1 is less than s2, return a value less than zero. If s1 is equal
|
|
to s2, return zero. If s1 is greater than s2, return a value greater
|
|
than zero. The comparison is based on the locale that is set with the
|
|
setlocale() function in the <locale.h> library. I will cover this
|
|
library in a later article. </p>
|
|
|
|
<p><b>strxfrm</b> transforms string s2 based on the locale category LC_COLLATE.
|
|
It then copies n bytes into string s1. Finally it returns the number
|
|
of characters actually placed into string s1. If y >= n then there
|
|
was an error. </p>
|
|
|
|
<p> </p>
|
|
|
|
<hr noshade>
|
|
<p><b><font size="+1">Search</font></b> </p>
|
|
|
|
<ul>
|
|
<tt>#include <string.h></tt>
|
|
<p><tt>void *memchr(const void *s, int c, size_t n);</tt> <br>
|
|
<tt>char *strchr(const char *s, int c);</tt> <br>
|
|
<tt>size_t *strcspn(const char *s, const char *reject);</tt> <br>
|
|
<tt>size_t *strspn(const char *s, const char *accept);</tt> <br>
|
|
<tt>char *strpbrk(const char *s, const char *accept);</tt> <br>
|
|
<tt>char *strchr(const char *s, int c);</tt> <br>
|
|
<tt>char *strrchr(const char *s, int c);</tt> <br>
|
|
<tt>char *strstr(const char *s, const char *substring);</tt> <br>
|
|
<tt>char *strtok(char *s, const char *delim);</tt></p>
|
|
|
|
</ul>
|
|
const void *s is the pointer to the array to be searched.<br>
|
|
int c is the character to search for.<br>
|
|
char *dest is a pointer to the array which will receive the copy.
|
|
<br>
|
|
const char *src is a pointer to the array from which the copy will
|
|
be made. <br>
|
|
size_t n is the number of characters to be copied.
|
|
<p><b>memchr</b> will search the memory array pointed to by s for character
|
|
c, up to n characters, returning a pointer to the first location, or NULL
|
|
if the character is not found in the memory array. </p>
|
|
|
|
<p><b>strcspn</b> returns the length of the beginning of the string s that
|
|
contains no characters in the reject string. </p>
|
|
|
|
<p><b>strspn</b> returns the length of the beginning of the string s that
|
|
contains only characters in the accept string. </p>
|
|
|
|
<p><b>strpbrk</b> returns a pointer to the location of the first character
|
|
in string s that matches any character in the accept string. Or a
|
|
NULL if c is not found in string s. </p>
|
|
|
|
<p><b>strchr</b> will search the string pointed to by s for character c, returning
|
|
a pointer to the first location, or NULL if the character is not found in
|
|
the string. </p>
|
|
|
|
<p><b>strrchr</b> returns a pointer to the location of the last character
|
|
in string s that matches the character represented by integer c. Or
|
|
a NULL of c is not found in s. </p>
|
|
|
|
<p><b>strstr</b> returns a pointer to the location of string substring in
|
|
string s, or a NULL if the substring is not found in s. </p>
|
|
|
|
<p>The <b>strtok</b> man page says that there are a lot of problems with this
|
|
function and says to never use the function. <b>strtok </b>takes a
|
|
string and divides it up into tokens. The first call to the function
|
|
has string s as its first argument and returns the first token. After
|
|
the first call the function is called with NULL as the first argument and
|
|
the function continues to return each token in turn until a NULL is returned
|
|
when there are no more tokens. The delimiter can be changed with each
|
|
call, or can be kept the same through all the calls. The limitations
|
|
of this function are many; the function modifies the original string
|
|
s, the value of the delimiter isn't retained between calls and the function
|
|
won't work with constant strings. </p>
|
|
|
|
<p> </p>
|
|
|
|
<hr noshade>
|
|
<p><b><font size="+1">Miscellaneous</font></b> </p>
|
|
|
|
<ul>
|
|
<tt>#include <string.h></tt>
|
|
<p><tt>void *memset(void *s, int c, size_t n);</tt> <br>
|
|
<tt>char *strerror(int errnum);</tt> <br>
|
|
<tt>size_t *strlen(const char *s);</tt> <br>
|
|
</p>
|
|
|
|
</ul>
|
|
void *s <br>
|
|
int c <br>
|
|
size_t n <br>
|
|
int errnum <br>
|
|
const char *s
|
|
<p><b>memset</b> fills memory array s of size n with the integer value in
|
|
c and returns a pointer to memory array s. </p>
|
|
|
|
<p><b>strerror</b> returns a pointer to the string that describes the errornum
|
|
passed as an argument, or an unknown error string if the errnum isn't known.
|
|
This works with various other error related functions in the <stdio.h>
|
|
and <error.h> libraries that a future article will have to cover in
|
|
great depth. </p>
|
|
|
|
<p><b>strlen</b> returns the number of characters in string s, not including
|
|
the '\0' string terminator. </p>
|
|
|
|
<p> </p>
|
|
|
|
<hr noshade>
|
|
<p><b><font size="+1">Non-Portable Functions</font></b> </p>
|
|
|
|
<p>The GNU string library has many that the Standard C Library doesn't.
|
|
The descriptions are taken out of the man pages cut and paste. If
|
|
you want your code to work on any Unix box then don't use these functions.
|
|
However, they are a good guide for implementing a function in your own code
|
|
that is portable. </p>
|
|
|
|
<p><tt>int strcasecmp(const char *s1, const char *s2);</tt> </p>
|
|
|
|
<p><b>strcasecmp</b> compares the two strings s1 and s2, ignoring
|
|
the case of the characters. It returns an integer less than,
|
|
equal to, or greater than zero if s1 is found, respectively,
|
|
to be less than, to match, or be greater than s2. </p>
|
|
|
|
<p><tt>int strncasecmp(const char *s1, const char *s2, size_t n);</tt> </p>
|
|
|
|
<p><b>strncasecmp</b> is similar, except it only compares the first n characters
|
|
of s1. </p>
|
|
|
|
<p><b>strcasecmp </b>and <b>strncasecmp</b> return an integer less than,
|
|
equal to, or greater than zero if s1 (or the first
|
|
n bytes thereof) is found, respectively, to be less than, to match, or be
|
|
greater than s2. </p>
|
|
|
|
<p><tt>char *strdup(const char *s);</tt> </p>
|
|
|
|
<p>I have implemented this function all on my own without knowing about this
|
|
function! I learn something new about Linux everyday. </p>
|
|
|
|
<p><b>strdup</b> returns a pointer to a new string which is a duplicate of
|
|
the string s. Memory for the new string is obtained
|
|
with malloc(3), and can be freed with free(3). </p>
|
|
|
|
<p><b>strdup</b> returns a pointer to the duplicated string, or NULL
|
|
if insufficient memory was available. </p>
|
|
|
|
<p><tt>char *strfry(char *string);</tt> </p>
|
|
|
|
<p><b>strfry</b> randomizes the contents of string by using rand(3) to randomly
|
|
swap characters in the string. The result is an anagram of
|
|
string. </p>
|
|
|
|
<p><b>strfry</b> returns a pointer to the randomized string. </p>
|
|
|
|
<p><tt>char *strsep(char **stringp, const char *delim);</tt> </p>
|
|
|
|
<p><b>strsep</b> returns the next token from the string
|
|
stringp which is delimited by delim. The token is terminated
|
|
with a `\0' character and stringp is updated to point past the token.
|
|
Similar to the strtok() function, but is non-portable. </p>
|
|
|
|
<p><b>strsep</b> returns a pointer to the token, or NULL if delim
|
|
is not found in stringp. </p>
|
|
|
|
<p><tt>char *index(const char *s, int c);</tt> </p>
|
|
|
|
<p><b>index</b> returns a pointer to the first occurrence of the character
|
|
c in the string s. We should probably just use the strchr() function,
|
|
it performs the same function in a portable manner. </p>
|
|
|
|
<p><tt>char *rindex(const char *s, int c);</tt> </p>
|
|
|
|
<p><b>rindex</b> returns a pointer to the last occurrence of the character
|
|
c in the string s. The terminating '\0' character is considered to
|
|
be a part of the strings. Please use the Standard C Library function
|
|
strrchr(), it performs the exact same function, in a portable manner. </p>
|
|
|
|
<p><b>index</b> and <b>rindex</b> return a pointer to the matched character
|
|
or NULL if the character is not found. </p>
|
|
|
|
<p> </p>
|
|
|
|
<hr noshade>
|
|
<h3> Corrections to previous articles:</h3>
|
|
That's right! I have <b>finally </b>gotten around to publishing
|
|
all the accumulated corrections to my previous articles. Just look
|
|
at all the mistakes that I have made! My thanks to those who
|
|
took the time to e-mail me after noticing a mistake in my articles. <br>
|
|
|
|
<p><b>Subject: The Standard C Library for Linux,
|
|
Part Three"</b> <br>
|
|
Date: Wed, 12 Aug 1998 11:27:08
|
|
+0200 <br>
|
|
From: Lars Hesdorf <hesdorf@ibm.net>
|
|
</p>
|
|
|
|
<p>Hej James M. Rogers </p>
|
|
|
|
<p>You wrote somewhere in
|
|
<A HREF="../issue32/rogers.html">The Standard C Library for Linux, Part Three</A> </p>
|
|
|
|
<p>"putchar writes a character to standard out. putchar(x) is the same
|
|
as <br>
|
|
fputc(x, STDIN)" </p>
|
|
|
|
<p>You probably meant "...fputc(x, STDOUT) </p>
|
|
|
|
<p>Lars Hesdorf <br>
|
|
HESDORF@IBM.NET </p>
|
|
|
|
<p>Reply: </p>
|
|
|
|
<p> Actually I think that I even got the capitalization wrong, I believe
|
|
that it should be "fputc(x, <b>stdout</b>)" The example program is
|
|
correct because I compiled and tested that for correctness. <br>
|
|
</p>
|
|
|
|
<p><b>Subject: The Standard
|
|
C Library for Linux, Part Two</b> <br>
|
|
Date:
|
|
Wed, 04 Aug 1999 21:00:59 +1000 <br>
|
|
From:
|
|
32000151 <32000151@snetmp.cpg.com.au> <br>
|
|
Organization: Student of Computer Power Institute <br>
|
|
</p>
|
|
|
|
<p>Dear Sir, </p>
|
|
|
|
<p>in <A HREF="../issue31/rogers1.html">The Standard C Library for Linux,
|
|
Part Two</A> you wrote </p>
|
|
|
|
<p>" char *fgets(char *s, int n, FILE *stream); </p>
|
|
|
|
<p>char *s the string that will hold the result. <br>
|
|
int n the maximum number of characters to read. <br>
|
|
FILE *stream is an already existing stream. <br>
|
|
. <br>
|
|
. <br>
|
|
. </p>
|
|
|
|
<p>fgets reads at most n characters from the stream into the string. </p>
|
|
|
|
<p> char s[1024]; <br>
|
|
FILE *stream; <br>
|
|
if((stream = fopen ("filename", "r")) != (FILE *)0)
|
|
{ <br>
|
|
while((fgets(s, 1023, stream)) !=
|
|
(char *)0 ) { <br>
|
|
<process each line>
|
|
<br>
|
|
} <br>
|
|
} else { <br>
|
|
<do fopen error handling>
|
|
<br>
|
|
} " </p>
|
|
|
|
<p>but fgets() actually reads up to n-1 characters, so it always has room
|
|
<br>
|
|
for the \0 (if n is set to the array size). </p>
|
|
|
|
<p>Tim McCormack <br>
|
|
32000151@bran.snetmp.cpg.com.au </p>
|
|
|
|
<p><b>Reply:</b> <br>
|
|
Thanks, I am going to have to make sure that I used this
|
|
function correctly in my example program. <br>
|
|
</p>
|
|
|
|
<p><b> Subject: snprintf in Article C Library for Linux?</b> <br>
|
|
Date: Tue, 01 Sep 1998 17:53:19 +0200 <br>
|
|
From: Renaud Hebert <hebert@bcv01y01.vz.cit.alcatel.fr>
|
|
</p>
|
|
|
|
<p>I didn't know snprintf, but I think that it is a clever thing to <br>
|
|
do to avoid overflowing the string buffer (much better than the evil
|
|
<br>
|
|
sprintf). </p>
|
|
|
|
<p>But that the first time I see it in a C library, so is-it a Linux only
|
|
<br>
|
|
function or is-it a "new" standard function which wasn't included in
|
|
<br>
|
|
HP-UX for example. </p>
|
|
|
|
<p>Maybe you could distinguish in your article, the standard library <br>
|
|
function and those Linux only. </p>
|
|
|
|
<p>Anyway this snprintf function is "A good Thing" TM. </p>
|
|
|
|
<p>Thanks for your articles, they are very well-written and very <br>
|
|
informative. <br>
|
|
-- <br>
|
|
__________________________________________________________________ <br>
|
|
Renaud HEBERT
|
|
CR2A-DI <br>
|
|
Software Developer </p>
|
|
|
|
<p><b>Reply:</b> <br>
|
|
I think that it is a GNU only thing. So you may want to
|
|
avoid using the snprintf function unless you only want your programs to
|
|
work in a GNU environment. I found a bunch of very useful GNU only
|
|
string functions and will taking your advice on pointing out those functions
|
|
that are only found in Linux. <br>
|
|
</p>
|
|
|
|
<p><b>Subject: Standard
|
|
C Programming Library Part 3</b> <br>
|
|
Date:
|
|
Sun, 20 Sep 1998 09:52:29 -0400 <br>
|
|
From:
|
|
Laurin Killian <lek@uconect.net> <br>
|
|
Organization:
|
|
Streamlined Development <br>
|
|
</p>
|
|
|
|
<p>Since you ask for corrections.... <br>
|
|
There are a couple of typos in your
|
|
<A HREF="../issue32/rogers.html">examples</A>: </p>
|
|
|
|
<p>------------you wrote: <br>
|
|
float x=99.1234; <br>
|
|
sprintf(string, "%d", x) <br>
|
|
------------should be... <br>
|
|
sprintf(string, "%f", x); <br>
|
|
|
|
^ <br>
|
|
------------you wrote: <br>
|
|
float x=99.1234; <br>
|
|
returnValue=sprintf(string, 4, "%d", x) <br>
|
|
------------should be... <br>
|
|
returnValue=snprintf(string, 5, "%f", x); <br>
|
|
|
|
^
|
|
^ ^ <br>
|
|
(to get the desired result of "99.1" - you need space for the null char)
|
|
</p>
|
|
|
|
<p>All the "scanf" type functions should have ampersands (&): <br>
|
|
scanf("%f%2d%d", &float1, &int1, &int2); </p>
|
|
|
|
<p>Hope this helps <br>
|
|
-Laurin </p>
|
|
|
|
<p><b>Reply:</b> <br>
|
|
Helps a lot, thank you! <br>
|
|
</p>
|
|
|
|
<p><b>Subject: character handling program</b>
|
|
<br>
|
|
Date: Mon, 15 Mar 1999 13:31:41
|
|
+0100 <br>
|
|
From: jorgen.tegner@sundsdefibrator.com
|
|
</p>
|
|
|
|
<p>Hi, </p>
|
|
|
|
<p>your code in Linux gazette is missing the setlocale() function call at
|
|
the <br>
|
|
beginning. That´s why you don´t get any <br>
|
|
useful results for characters above 127 as programs start out in the
|
|
C locale by <br>
|
|
default. Also, isalpha(), toupper() <br>
|
|
and tolower() are not restricted to the A-Za-z range. </p>
|
|
|
|
<p>Regards, <br>
|
|
Jörgen Tegnér </p>
|
|
|
|
<p><b>Reply:</b> <br>
|
|
Absolutely right, I am saving setlocale() for when I cover <locale.h>.
|
|
:) </p>
|
|
|
|
<p> </p>
|
|
|
|
<hr noshade>
|
|
<h4> Bibilography:</h4>
|
|
<i>The ANSI C Programming Language, Second Edition</i>, Brian W. Kernighan,
|
|
Dennis M. Ritchie, Printice Hall Software Series, 1988
|
|
<p><i>The Standard C Library</i>, P. J. Plauger, Printice Hall P T R, 1992
|
|
</p>
|
|
|
|
<p><i>The Standard C Library, Parts 1, 2, and 3</i>, Chuck Allison, <i>C/C++
|
|
Users Journal</i>, January, February, March 1995 </p>
|
|
|
|
<p>STRING(3), BSD MANPAGE, <i>Linux Programmer's Manual</i> <br>
|
|
</p>
|
|
|
|
<hr noshade>
|
|
<center> <i>
|
|
<h4>Previous "The Standard C Library for Linux" Articles</h4>
|
|
</i></center>
|
|
<i> <a href="../issue24/rogers.html">The Standard
|
|
C Library for Linux, stdio.h, January 1998</a><br>
|
|
<a href="../issue31/rogers1.html">The Standard
|
|
C Library for Linux, stdio.h, August 1998</a><br>
|
|
<a href="../issue32/rogers.html">The Standard
|
|
C Library for Linux, stdio.h, September 1998</a><br>
|
|
<a href="../issue38/rogers.html">The Standard
|
|
C Library for Linux, ctype.h, March 1999</a><br>
|
|
<a href="../issue39/rogers.html">The Standard
|
|
C Library for Linux, stdlib.h, April 1999</a><br>
|
|
<a href="../issue41/rogers.html">The Standard
|
|
C Library for Linux, assert.h, May 1999</a><br>
|
|
</i> <br>
|
|
|
|
|
|
<!-- *** BEGIN bio *** -->
|
|
<SPACER TYPE="vertical" SIZE="30">
|
|
<P>
|
|
<H4><IMG ALIGN=BOTTOM ALT="" SRC="../gx/note.gif">James Rogers</H4>
|
|
<EM>James Rogers is a systems programmer specializing in the area of Cloverleaf
|
|
HL7 routers. He is also currently working on an open source library of HL7
|
|
routines. He hopes to use this library to write an open source HL7
|
|
interface engine.</EM>
|
|
|
|
|
|
<!-- *** END bio *** -->
|
|
|
|
<!-- *** BEGIN copyright *** -->
|
|
<P> <hr> <!-- P -->
|
|
<H5 ALIGN=center>
|
|
|
|
Copyright © 2002, James M Rogers.<BR>
|
|
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
|
|
Published in Issue 76 of <i>Linux Gazette</i>, March 2002</H5>
|
|
<!-- *** END copyright *** -->
|
|
|
|
<!--startcut ==========================================================-->
|
|
<HR><P>
|
|
<CENTER>
|
|
<!-- *** BEGIN navbar *** -->
|
|
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="qubism.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue76/rogers.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="spiel.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
|
|
<!-- *** END navbar *** -->
|
|
</CENTER>
|
|
</BODY></HTML>
|
|
<!--endcut ============================================================-->
|