The program consists of 3 files: demo.c
, mylib.c
and mylib.h
. The code is heavily commented.
demo.c:
/***********************************************************************
*
* This is a program that prompts the user for an input string using a
* custom input function.
*
***********************************************************************/
#include <stdio.h> /* printf */
#include <stdlib.h> /* exit */
#include "mylib.h"
/* For testing purposes, let's make the length of the string 4 */
#define STRING_LENGTH 4
int main(int argc, char* argv[]) {
char* s = udf_get_input("Prompt: ", STRING_LENGTH);
printf("You entered: \"%s\"\n", s);
/* I put quotes around the string to better see
what has actually been entered */
free(s);
s = NULL; /* This is not really necessary */
exit(EXIT_SUCCESS);
}
mylib.h:
#ifndef MYLIB_H_
#define MYLIB_H_
size_t udf_strlen(const char* s);
char* udf_get_input(const char* const prmpt, int str_len);
#endif /* MYLIB_H_ */
mylib.c:
#include <stdio.h> /* printf, getchar */
#include <stdlib.h> /* malloc, realloc, free, exit */
#define ERROR_MSG "error: could not allocate enough memory"
/***********************************************************************
*
* This is just my own implementation of the C Standard Library's
* strlen function. We're going to need it later.
*
***********************************************************************/
size_t udf_strlen(const char* s) {
size_t i = 0;
while (*s++) {
i++;
}
return i;
}
/***********************************************************************
*
* This is a function that takes in as arguments a pointer to a string
* that represents the prompt the user sees when typing things at the
* keyboard and the length of the string. The function returns a pointer
* to the string that has been entered.
*
* How it works:
* We are going to allocate a certain number of bytes on the heap. This
* is going to be our buffer. Then we will read whatever the user types
* in into that buffer. After that, we will check if we need to tweak
* the amount of memory that the string takes up so that no memory is
* wasted unnecessarily. If the number of characters entered by the user
* exceeds the buffer size, the rest of the string is discarded.
*
***********************************************************************/
char* udf_get_input(const char* const prmpt, int str_len) {
int buffer_size = str_len + 1; /* Number of characters allowed to be
entered plus one to accommodate
the null character */
char* buffer; /* Temporary storage for the user's string */
if (!(buffer = malloc(buffer_size * sizeof(char)))) {
printf("%s\n", ERROR_MSG);
exit(EXIT_FAILURE);
}
printf("%s", prmpt); /* Display the prompt */
int ch; /* Stores characters retrieved from stdin */
char* p = buffer; /* Temporary pointer to traverse the buffer */
while ((ch = getc(stdin)) != EOF) {
/* If the character read is a newline character or buffer_size - 1
characters have been already entered, terminate the string with a
null character and bail out of the loop */
if (ch == '\n' || !--buffer_size) {
*p = '\0';
break;
}
*p++ = ch;
}
/* If buffer_size is more than zero, that means there are unused bytes in
the buffer. So, we will reallocate memory to shirk it so that the string
occupies as much memory as exactly necessary. Otherwise no memory
reallocation is needed and we can skip this step. */
if (buffer_size) {
buffer = realloc(buffer, (udf_strlen(buffer) + 1) * sizeof(char));
if (!buffer) {
printf("%s\n", ERROR_MSG);
exit(EXIT_FAILURE);
}
}
return buffer; /* Return the pointer to the string stored on the heap */
}
To test the program, make a separate directory and create these three files in it:
touch demo.c mylib.c mylib.h
To run the program, execute this command:
gcc -c demo.c mylib.c && \
gcc demo.o mylib.o -o a.out && \
./a.out
udf_get_input()
1) this line:if (ch == '\n' || !--buffer_size) {
, when a full buffer of data is input, will result in the '\0' being written past the end of the buffer. Suggest the check for buffer full and check for '\n' be part of thewhile()
statement. To do that , use:buffer_size>0 &&
2) when callingrealloc()
, always assign to a temp pointer, the check (!=NULL) the temp pointer and if not NULL, then assign to the target (buffer) pointer. Otherwise a memory leak will occur \$\endgroup\$sizeof(char)
is defined in the C standard as 1. Multiplying anything by 1 has no effect. The expression, as part of the parameter torealloc()
just clutters the code. Suggest removing that expression. \$\endgroup\$stddef.h
2) the parameters to function: main() are not used. Suggest the main() signature be:int main( void )
3) in function:udf_get_input()
, thestr_len
parameter should be typesize_t
andbuffer_size
should be type:size_t
. When compiling, always enable all the warnings, then fix those warnings. \$\endgroup\$stderr
, notstdout
and when a system function fails, suggest using:perror()
so the enclosed text and the reason the OS thinks the error occurred are both output tostderr
. \$\endgroup\$If buffer_size is more than zero, that means there are unused bytes in the buffer.
is not necessarily true. Strongly suggest removing the call torealloc()
and the associated code. \$\endgroup\$