Trying to salve my frustration with the scanf() function, I decided in last week’s Lesson to try to use scanf() to build a string. Because the function terminates standard input at the first whitespace character (space, tab, newline), the strings input must be stored and the string built in memory.
The first change I made is to get rid of the buffer[]
array and replace it with a pointer. This move may seem redundant, as pointer s
is already used in the code to store the string. But I want to build a string. Therefore having one buffer for input and another for creating the string makes sense.
2023_07_15-Lesson-a.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #define SIZE 16 int main() { char *b,*s; /* allocate/initalize buffers */ b = malloc( SIZE * sizeof(char) ); /* input */ s = malloc( SIZE * sizeof(char) ); /* string */ if( b==NULL || s==NULL ) { fprintf(stderr,"Memory allocation error\n"); exit(1); } /* initialize string storage */ *b = *s = '\0'; /* fetch input */ printf("Word: "); scanf("%s",b); /* copy the word */ strcpy(s,b); /* output results */ puts(s); return(0); }
The code allocates storage for both pointers b
and s
, setting the size to SIZE
or 16 characters (15 characters plus one for the null character). Remember: the scanf() function does not do bounds checking! Don’t input a long string just to see what happens and don’t ever use scanf() in this manner in code you plan on releasing or even using non-experimentally.
Both strings are tested for success: if( b==NULL || s==NULL )
. If either string is NULL
, the program mercifully stops.
The strings are initialized, setting each to a null string: *b = *s = '\0';
This step may not be necessary, though I want to ensure that *b
and *s
are “real” strings.
The rest of the code works like the original shown in last week’s Lesson. I added a printf() statement to output a prompt. Here’s a sample run:
Word: hello
hello
The next step is to add a loop to collect words and build the string. This improvement requires a major change: Pointer s
must be reallocated each iteration of the loop to append the new word input:
2023_07_15-Lesson-b.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #define SIZE 16 int main() { char *b,*s; /* allocate/initialize buffers */ b = malloc( SIZE * sizeof(char) ); /* input */ s = malloc( sizeof(char) ); /* string */ if( b==NULL || s==NULL ) { fprintf(stderr,"Memory allocation error\n"); exit(1); } /* initialize string storage */ *b = *s = '\0'; while(1) { /* fetch input */ printf("Word: "); scanf("%s",b); /* copy the word */ /* add two: space and null char */ s = realloc(s,strlen(s) + strlen(b) + 2); if( s==NULL ) { fprintf(stderr,"Reallocation error\n"); exit(1); } strcat(s,b); strcat(s," "); } /* output results */ puts(s); return(0); }
Pointer s
is allocated only a single character of storage for the null character: s = malloc( sizeof(char) );
This improvement builds a short string, but it comes in handy when storage is reallocated later.
And endless while loop builds the string: while(1)
Within the loop, the scanf() function fetches input. The next statement reallocates storage for pointer s
:
s = realloc(s,strlen(s) + strlen(b) + 2);
The pointer’s new size s
is is based on its current size (strlen(s)
) plus the length of the string input (strlen(b)
) plus two. The two extra characters are for a space to separate the words and the null character.
The ralloc() function retains the original memory buffer contents. The result is a buffer that contains the original string plus storage for the new string input.
Two strcat() functions build the string. The first adds the input word. The second appends a space character.
Output doesn’t happen, however, as the loop is endless. Further, why always append a space? Strings are more than words and spaces. I address these issues in next week’s Lesson.