Lecture 9: Strings and Other Things
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Be Careful When freeing Strings or Any pointer object
*** Watch out for aliases ***
- an alias is a "synonym" of another object. for example:
char p[100] = "hi";
char *p2;
p2 = p; /* this doesn't copy; two pointers to the same series of chars */
- now p2 is an alias for p. What if we try to free both p and p2?
free p;
free p2; /* oops! */
- remember the function call free returns the memory for an object
to the system so you can no longer use it.
*** Watch out for uninitialized pointers ***
- just like anything else, ALWAYS initialize a pointer before
using it!
- you can't do *p or p[i] until p points to something.
- consider the following incorrect example:
char *s1;
char s2[] = "hello";
int i;
for (i=0; i<6; i++)
s1[i] = s2[i]; /* oops: we haven't allocated space for s1 */
free(s1) /* Worse! s1 doesn't point to anything! */
free(s2) /* Also bad. We didn't allocate s2 using malloc */
*** Watch how you compare strings ***
- just as we can't copy a string using s1 = s2, we can't compare
a string using s1 == s2. This compares the pointers, not the
contents of the string. If s1 is an alias of s2, then s1 == s2
will return true but otherwise, it will return false:
for example:
char s1[] = "hi";
char s2[3];
scanf("%s",s2);
/* Even if the user types in "hi", the following will be false: */
s1 == s2;
In order to compare two strings use the string library ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The string library:
- we use strings a lot so there are library functions for
doing the most common string operations:
#include
/* copy string t into string s, return s (remember to malloc space for
s first! */
char *strcpy(char *s, char *t);
/* compare s to t;
return <0 if s0 if s>t
*/
int strcmp(char *s, char *t);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A Larger Example Using Strings and Pointers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include
#include
/* Scan in the next word(sequence of non-whitespace characters)
Allocate space for the word and return a pointer to it. */
char *scan_word(void)
{
char *s, *temp;
char current;
int i, maxsize = 30;
scanf("%c", ¤t);
while (current == '\t' ||
current == ' ' ||
current == '\n'){
scanf("%c", ¤t);
}
s = (char *)malloc(maxsize*sizeof(char));
i = 0;
while(current != '\t' &&
current != ' ' &&
current != '\n'){
/* Check to see if we have enough room in s.
If not, then enlarge the string */
if (i == maxsize - 2) {
maxsize = maxsize * 2;
temp = (char *)malloc(maxsize * sizeof(char));
/* We must have '\0' at the end of the string for strcpy: */
s[i] = '\0';
strcpy(temp, s);
/* Once we have copied the contents of the string, we delete
the old copy */
free(s);
s = temp;
}
s[i] = current;
i++;
scanf("%c", ¤t);
}
/* Remember to tack on the NULL character */
s[i] = '\0';
return s;
}
/* Addresses will be represented as a structure: */
struct address {
int num;
char *street;
char *city;
int zip;
};
/* Scan in and allocate space for an address. Return a pointer
to that address. */
struct address *scan_address(void)
{
struct address *addr;
int num;
char *s;
addr = (struct address *)malloc(sizeof(struct address));
scanf("%d", &(*addr).num);
(*addr).street = scan_word();
(*addr).city = scan_word();
scanf("%d", &(*addr).zip);
return addr;
}
/* Names */
struct name{
char *last;
char *first;
char initial;
};
/* Scan and allocate space for a name. Return a pointer to
that name. */
struct name *scan_name(void)
{
struct name *n;
n = (struct name *)malloc(sizeof(struct name));
(*n).last = scan_word();
(*n).first = scan_word();
scanf("%c", &(*n).initial);
return n;
}
/* Compare n1 and n2 by last name, then first name, then initial.
If n1 < n2 return -1
If n1 == n2 return 0
If n1 > n2 return 1
*/
int compare_name(struct name *n1, struct name *n2)
{
int res = strcmp((*n1).last, (*n2).last);
if (res != 0)
return res;
else {
res = strcmp((*n1).first, (*n2).first);
if (res != 0)
return res;
else if ((*n1).initial < (*n2).initial)
return -1;
else if ((*n1).initial == (*n2).initial)
return 0;
else
return 1;
}
}
/* A phonebook entry */
struct entry {
struct name *n;
struct address *addr;
char *phone;
};
/* Allocate space for and scan in a phonebook entry */
struct entry *scan_entry(void)
{
struct entry *e = (struct entry *)malloc(sizeof(struct entry));
(*e).n = scan_name();
(*e).addr = scan_address();
(*e).phone = scan_word();
return e;
}