Defining an automatic string:
It is defined within a block or within the whole file. Memory
allocation and deallocation is controlled automatically by the system -- allocate
when it is declared, and deallocatte on leaving the block.
#define MAXLINE 256
char word[MAXLINE];
scanf("%s", word);
printf("%s", word);
Creating a string:
/* the following three are equivalent */
char filename[12] = "sensor1.dat";
char filename[] = "sensor1.dat";
char filename[] = {'s','e','n','s','o','r','1','.','d','a','t','\0'};
A string function example:
Here is a function which reads in a string from standard input.
The idea is to read in one character at a time until a newline is
found, and
then put in the string terminator character.
/* getline: read a line into s and return its length*/
int getline(char s[], int limit) {
int c, i;
c = getchar();
for (i=0; c != '\n'; i++) {
if (c == EOF) {
s[i] = '\0';
return i;
}
if (i == limit-1) {
s[i] = '\0';
return i;
}
s[i] = c;
c = getchar();
}
s[i] = '\n';
if (i != limit-1) /* in case no room for terminator */
i++;
s[i] = '\0';
return i;
}
Notes:
- We must provide a limit
value which is the size of the array so that we do not put in
characters past
the end.
- In Java, trying to put in more characters than will fit
causes
a runtime error which will terminate your program.
- If you do this in C:
- You probably will not get an error message when the error
occurs.
- An error may appear at a later part of your program.
- The error message you get may have nothing to do with what caused the
error.
- The program might seem to run correctly, but compute an
incorrect
value.
- Almost anything can happen.
- What does the string look like if an EOF is reached
before a newline?
- What does the string look like if too many characters are
entered?
- What does the variable limit represent?
Ans: the amount of space in the array s
- What is the maximum length of the string?
Here is a test program for getline:
#include <stdio.h>
#define MAXLINE 10
int getline(char line[], int maxline);
int main() {
int len;
int i;
char line[MAXLINE];
len = getline(line,MAXLINE);
printf("The line has length %d and the array is\n",len);
for (i=0; i < MAXLINE; i++) {
printf("%3d: %c = %d\n",i,line[i],(int)line[i]);
if (line[i] == '\0')
break;
}
return 0;
}
Sample output:
% getlinetest1
abc
The line has length 4 and the array is
0: a = 97
1: b = 98
2: c = 99
3:
= 10
4: = 0
pandora%
Test 2:
% getlinetest1
abcdefghijklmnop
The line has length 9 and the array is
0: a = 97
1: b = 98
2: c = 99
3: d = 100
4: e = 101
5: f = 102
6: g = 103
7: h = 104
8: i = 105
9: = 0
pandora%
Test 3:
% getlinetest1
abc^D^DThe line has length 3 and the array is
0: a = 97
1: b = 98
2: c = 99
3: = 0
pandora%
Note: The two ^D^D indicate pushing the D-key while
holding down Control.
They do not appear on the screen.
A complete set of test would consist of:
- just RETURN
- one character then RETURN
- 8 characters then RETURN
- 9 characters then RETURN
- 10 characters then RETURN
- EOF after 0 characters
- EOF after 1 character
- EOF after 8 characters
- EOF after 9 characters
- EOF after 10 characters
Why didn't we write the test program with MAXLINE 1000?
Here is another version of getline
int getline(char s[], int lim) {
int c, i;
for (i = 0; i < lim-1 && (c=getchar()) != EOF && c != '\n'; ++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
Notes:
I prefer the use of a while loop.
(Which one is easier to understand?)
There is a library version of getline called gets
but it takes only one parameter, an array of characters,
and does not check for overflow.
This is very bad!
String copy functions:
/* strcpy: copy t to s; array subscript version */
void strcpy(char s[], char t[]) {
int i;
i = 0;
while( (s[i] = t[i]) != '\0')
++i;
}
/* strcpy: copy t to s; pointer version 1 */
void strcpy(char *s, char *t) {
while( (*s = *t) != '\0') {
s++;
t++;
}
}
/* strcpy: copy t to s; pointer version 2 */
void strcpy(char *s, char *t) {
while( (*s++ = *t++) != '\0')
;
}
/* strcpy: copy t to s; pointer version 3 */
void strcpy(char *s, char *t) {
while(*s++ = *t++)
;
}
Notes:
- The first part of the expression in the while is an
assignment.
- An assignment returns a value, the value assigned.
- The value is compared to '\0'
- The pointer versions use pointer arithmetic.
- The last version uses the fact that a while continues
until its condition is false, that is, 0, which in this case
is supplied by the null character at the end of the string.
Strings and Pointers:
When managing a string, one must remember that it is an array of
char. But, when passing a string, the formal heading of the
function could be either of the headings
below.
void doStuff (char word []) or
void doStuff(char * word)
In either case the string can be manipulated like an array...or like a
pointer.
(This holds true for any array also.)
However, there is a tremendous difference between the following:
char word[MAXLINE]; and
char * word;
Notes:
- The array definition actually reserves memory for the characters of
the string.
- The char * version DOES NOT reserve memory for anything put a
pointer to the string. There is NO MEMORY SPACE AT ALL for the
characters of the string. Room for these characters will usually be
created using malloc.
There is also a tremendous difference between the following:
char *s = NULL; and
char *t = "";
Notes:
- In the first example s is the null pointer -- usually just
an address of 0 (the number "zero") is stored in the pointer,
although this is not required. There is no storage for characters.
If you try to print this string using
printf("%s", s); you will get a segmentation fault.
- In the second t is actually a string, with length zero.
The only character is the null character which must be
at the end of every string. (This final null character does not
count as part of the length.) As a pointer, t is
not null, put points to the single null character.
If you try to print this with printf("%s", t);
nothing will be printed, but there will be no error.
<string.h>
The following functions are found in <string.h>
- int strlen (const char * s)
- returns the int length of s
- char * strcpy (char * s, const char * t)
- returns a pointer to s with t copied to s
- char * strncpy (char * s, const char * t, int n)
- returns a pointer to s with n characters of t as s
- char * strcat (char * s, const char * t)
- returns a pointer to s with t concatenated to the end of s
- char * strncat (char * s, const char * t, int n)
- returns a pointer to s with n characters of t concatenated to the end of s
- int strcmp (const char * s, const char * t)
- compares s and t, returns 0 if s == t, negative value if s < t, and positive if s > t
- int strncmp (const char * s, const char * t, int n)
- compares first n characters of s and t, returns 0 if s == t, negative
value if s < t, and positive if s > t
- char * strchr (const char * s, char c)
- returns pointer to first character c in s, null otherwise
- char * strrchr (const char * s, char c)
- returns pointer to last character c in s, null otherwise
- char * strstr (const char * s, const char * t)
- returns a pointer to the first character of the string t found in s, null otherwise
- char * strdup (const char * s)
- duplicates the string to a new dynamic string with it's own memory... a true duplicate
There are more...
From the manual
- The arguments s, s1, and s2
point
to strings (arrays of characters
terminated
by a null character). The strcat(),
strncat(), strcpy(), strncpy(), strtok(), and
strtok_r() functions all alter their first
argument. These functions do not check
for overflow of the array pointed to
by the first argument.
To control input, error handling can be done using some useful functions in
<stdlib.h>. You will notice from time to time that if you
enter a string
instead of a number (as a program may be expecting) the string will crash
your program. To avoid this, input everything as a string and
convert to values as you see fit.
Here are some helpful functions.
- double atof (const char * s)
- int atoi (const char * s)
- long int atol (const char * s)
Run this to see dangerous usage of string function.
So how can we avoid string
overflow???
- Always allocate memory for strings.
- Make sure to reserve enough memory.
Copyright © 2011, Neal R. Wagner. Permission is granted
to access, download, share, and distribute, as long as this notice remains.