Xavoux said:
Hello all...
I can't remind which function to use for safe inputs...
gets, fgets, scanf leads to buffer overflow...
grade.c shows how to use fscanf for the safe input of strings
for the specific case of when it is OK to ignore
input that excedes the size of the input buffer.
The strings can then be converted to numeric data.
pops_device.c also shows how to use fscanf
for the safe input of strings
for the specific case of when it is OK to ignore
input that excedes the size of the input buffer.
line_to_string.c shows how to read strings of arbitrary
length into a linked list, using dynamic allocation.
/* BEGIN grade.c */
#include <stdlib.h>
#include <stdio.h>
#define LENGTH 3
#define str(x) # x
#define xstr(x) str(x)
int main(void)
{
int rc;
char array[LENGTH + 1];
long number;
const char letter[4] = "DCBA";
fputs("Enter the Numeric grade: ", stdout);
fflush(stdout);
rc = fscanf(stdin, "%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) {
getc(stdin);
}
while (rc == 1) {
number = strtol(array, NULL, 10);
if (number > 59) {
if (number > 99) {
number = 99;
}
array[0] = letter[(number - 60) / 10];
switch (number % 10) {
case 0:
case 1:
array[1] = '-';
array[2] = '\0';
break;
case 8:
case 9:
array[1] = '+';
array[2] = '\0';
break;
default:
array[1] = '\0';
break;
}
} else {
array[0] = 'F';
array[1] = '\0';
}
printf("The Letter grade is: %s\n", array);
fputs("Enter the Numeric grade: ", stdout);
fflush(stdout);
rc = fscanf(stdin, "%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) {
getc(stdin);
}
}
return 0;
}
/* END grade.c */
/* BEGIN pops_device.c */
/*
** If rc equals 0, then an empty line was entered
** and the array contains garbage values.
** If rc equals EOF, then the end of file was reached,
** or there is some output problem.
** If rc equals 1, then there is a string in array.
** Up to LENGTH number of characters are read
** from a line of a text stream.
** If the line is longer than LENGTH,
** then the extra characters are discarded.
*/
#include <stdio.h>
#define LENGTH 50
#define str(x) # x
#define xstr(x) str(x)
int main(void)
{
int rc;
char array[LENGTH + 1];
puts("The LENGTH macro is " xstr(LENGTH));
fputs("Enter a string with spaces:", stdout);
fflush(stdout);
rc = fscanf(stdin, "%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) {
getc(stdin);
}
while (rc == 1) {
printf("Your string is:%s\n\n"
"Hit the Enter key to end,\nor enter "
"another string to continue:", array);
fflush(stdout);
rc = fscanf(stdin, "%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) {
getc(stdin);
}
if (rc == 0) {
*array = '\0';
}
}
return 0;
}
/* END pops_device.c */
/* BEGIN line_to_string.c */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
/*
** INITIAL_BUFFER_SIZE can be any number.
** Lower numbers are more likely
** to get a non-NULL return value from malloc.
** Higher numbers are more likely to prevent
** any further allocation from being needed.
*/
#define INITIAL_BUFFER_SIZE 0
struct list_node {
struct list_node *next;
void *data;
};
int line_to_string(FILE *fp, char **line, size_t *size);
struct list_node *string_node(struct list_node **head,
struct list_node *tail,
char *data);
void list_free(struct list_node *node, void (*free_data)(void *));
int list_fputs(FILE *stream, struct list_node *node);
int main(void)
{
struct list_node *head, *tail;
int rc;
char *buff_ptr;
size_t buff_size;
long unsigned line_count;
buff_size = INITIAL_BUFFER_SIZE;
buff_ptr = malloc(buff_size);
if (buff_ptr == NULL && buff_size != 0) {
printf("malloc(%lu) == NULL\n", (long unsigned)buff_size);
exit(EXIT_FAILURE);
}
tail = head = NULL;
line_count = 0;
puts(
"\nThis program makes and prints a list of all the lines\n"
"of text entered from standard input.\n"
"Just hit the Enter key to end,\n"
"or enter any line of characters to continue."
);
while ((rc = line_to_string(stdin, &buff_ptr, &buff_size)) > 1) {
++line_count;
tail = string_node(&head, tail, buff_ptr);
if (tail == NULL) {
break;
}
puts(
"\nJust hit the Enter key to end,\n"
"or enter any other line of characters to continue."
);
}
switch (rc) {
case EOF:
if (buff_ptr != NULL && strlen(buff_ptr) != 0) {
puts("rc equals EOF\nThe string in buff_ptr is:");
puts(buff_ptr);
++line_count;
tail = string_node(&head, tail, buff_ptr);
}
break;
case 0:
puts("realloc returned a null pointer value");
if (buff_size > 1) {
puts("rc equals 0\nThe string in buff_ptr is:");
puts(buff_ptr);
++line_count;
tail = string_node(&head, tail, buff_ptr);
}
break;
default:
/*
** If rc were to be evaluated at this point in the code,
** the value of rc
** would now be equal to (1 + strlen(buff_ptr)).
*/
break;
}
if (line_count != 0 && tail == NULL) {
puts("Node allocation failed.");
puts("The last line entered didn't make it onto the list:");
puts(buff_ptr);
}
free(buff_ptr);
puts("\nThe line buffer has been freed.\n");
printf("%lu lines of text were entered.\n", line_count);
puts("They are:\n");
list_fputs(stdout, head);
list_free(head, free);
puts("\nThe list has been freed.\n");
return 0;
}
int line_to_string(FILE *fp, char **line, size_t *size)
{
int rc;
void *p;
size_t count;
count = 0;
while ((rc = getc(fp)) != EOF) {
++count;
if (count + 2 > *size) {
p = realloc(*line, count + 2);
if (p == NULL) {
if (*size > count) {
(*line)[count] = '\0';
(*line)[count - 1] = (char)rc;
} else {
ungetc(rc, fp);
}
count = 0;
break;
}
*line = p;
*size = count + 2;
}
if (rc == '\n') {
(*line)[count - 1] = '\0';
break;
}
(*line)[count - 1] = (char)rc;
}
if (rc != EOF) {
rc = count > INT_MAX ? INT_MAX : count;
} else {
if (*size > count) {
(*line)[count] = '\0';
}
}
return rc;
}
struct list_node *string_node(struct list_node **head,
struct list_node *tail,
char *data)
{
struct list_node *node;
node = malloc(sizeof *node);
if (node != NULL) {
node -> next = NULL;
node -> data = malloc(strlen(data) + 1);
if (node -> data != NULL) {
if (*head == NULL) {
*head = node;
} else {
tail -> next = node;
}
strcpy(node -> data, data);
} else {
free(node);
node = NULL;
}
}
return node;
}
void list_free(struct list_node *node, void (*free_data)(void *))
{
struct list_node *next_node;
while (node != NULL) {
next_node = node -> next;
free_data(node -> data);
free(node);
node = next_node;
}
}
int list_fputs(FILE *stream, struct list_node *node)
{
while (node != NULL
&& fputs(node -> data, stream) != EOF
&& putc( '\n', stream) != EOF)
{
node = node -> next;
}
return node == NULL ? '\n' : EOF;
}
/* END line_to_string.c */