Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have got a really weird issue. After using fgets to read/type a string pointer the next time i want to read a new string from the keyboard the first character automatically becomes \n. How can i avoid/overwrite that ?
I've tried to use
if (firstString[strlen(firstString) - 1] == '\n')
firstString[strlen(firstString) - 1 ] = 0;
but it's still not working.
Thanks for help.
Here is my code :
void citire_text (char *text , int numar_linii)
{
char *text_linie;
int i;
for(i=0;i<=numar_linii;i++)
{
char *text_linie;
text_linie = malloc(MAX*sizeof(char));
fgets(text_linie,MAX,stdin);
strcat(text,text_linie);
}
if (text[strlen(text) - 1] == '\n')
text[strlen(text) - 1 ] = 0;
}
void citire_operatie (char *operatie)
{
fgets(operatie,MAX+2,stdin);
printf("%d",*operatie);
if ((*operatie)=='\n')
printf("YES");
else
printf("NO\n");
}
int main(void)
{
char *text,*operatii;
int numarDeLinii,i;
scanf("%d",&numarDeLinii);
text = malloc(MAX*numarDeLinii*sizeof(char));
operatii = malloc((MAX+2)*sizeof(char));
citire_text(text,numarDeLinii);
int numar_operatii;
scanf("%d",&numar_operatii);
for(i = 1;i<= numar_operatii;i++)
citire_operatie(operatii);
return 0;
}
If i set "numar_operatii" to 1 , in the subprogram citire_operatie fgets won't be even called.
Best to not mix scanf() functions with fgets(). There is a '\n' left-over from when code read scanf("%d", ...
Instead of
scanf("%d",&numarDeLinii);
Read with fgets()
char buf[80];
if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EOF();
if (sscanf(buf, scanf("%d",&numarDeLinii) != 1) Handle_Nonnumeric_Input();
Or make a simple helper function to read an int. Something like:
int Read_int(FILE *istream, const char * prompt, int *dest) {
char buf[80];
while (fgets(buffer, sizeof buffer, stdin)) {
fputs(prompt, stdout);
fflush(stdout);
if (sscanf(buffer, "%d", dest) == 1) return 1;
}
return EOF;
}
// Usage
if (Read_int(stdin, "Enter lines", &numarDeLinii) != 1) return FAIL;
if (Read_int(stdin, "Enter operations", &numar_operatii) != 1) return FAIL;
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Safe input is harder than I thought. I looked around and found this, but it is from 2011 and things might have changed since then.
I'm looking for something that can handle string input and single character input. For example:
Hello, what's your name?
My name is: _
Are you sure?
[Y] Yes, hello
[N] No, goodbye
_
Here is the way I'm doing it right now:
char input[16];
fgets(input, 16, stdin);
char input = getchar();
My problem has always been that the user may input arbitrarily long input or invalid input. How can I read input safely and ensure future inputs won't get borked?
Looking for solutions that work in C and across Linux / Windows.
Thank you for your time.
You are able to read infinite standard input safely. You can just use a continuously reallocating buffer.
#include <stdio.h>
#include <stdlib.h>
char* get_line(size_t* length) {
size_t len = 0;
size_t cap = 4;
char* buffer = malloc(cap);
if (buffer == NULL) {
fprintf(stderr, "Virtual memory exhausted\n");
return NULL;
}
char current;
while ((current = getchar()) != '\n') {
if (len + 1 > cap) {
cap *= 2;
buffer = realloc(buffer, cap);
}
buffer[len++] = current;
}
// One last time for NUL terminator
if (len + 1 > cap) {
cap *= 2;
buffer = realloc(buffer, cap);
}
buffer[len] = 0;
if (length) *length = len;
return buffer;
}
This function will read stdin char-by-char and add it to a string which is returned. Optionally you can ask for its length. Don't forget to free.
int main() {
char* line = get_line(NULL);
printf("You entered: %s\n", line);
free(line);
}
NOTE: This code is meant to be of little verbosity so some checks were omitted. In production code checking realloc and using int for getchar() to test for EOF is necessary.
Alright, bear with me because there's some weird stuff here.
I'm currently trying to implement a SUPER simple shell with max 20 char commands and no piping, etc. I'm also learning C along with it so please forgive any egregious errors or usage.
Here's my code for a parser:
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int running = 1;
/* Main loop */
while(running==1) {
// The max size of the input is 20 bytes
char input[20];
// Read string from user
fgets(input, sizeof(input), stdin);
/* ----- PARSE INPUT ----- */
char buffer[20];
for(int i = 0; i < sizeof(input); i++) {
buffer[i] = input[i];
/* ------ CHECK BUFFER AGAINST VARIOUS COMMANDS ----- */
// TALK TO THE HAND
if (strcmp(buffer, "TALK TO THE HAND") == 0) {
// execute TALK TO THE HAND
printf("TALK TO THE HAND\n");
}
else {
printf("WHAT DID I DO WRONG?\n");
}
}
}
}
My expected output when inputting TALK TO THE HAND is just it echoing that, but what I get is this:
TALK TO THE HAND
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
TALK TO THE HAND
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
WHAT DID I DO WRONG?
and I have no idea why it seemingly loops over and over again with different outputs.
Code iterates too far
Iterate to the length of the string, not the size of the buffer.
// for(int i = 0; i < sizeof(input); i++) {
for(int i = 0; input[i]; i++) {
In any case, this iteration is not needed. Just compare to input
//if (strcmp(buffer, "TALK TO THE HAND") == 0) {
if (strcmp(input, "TALK TO THE HAND") == 0) {
If code wants to copy a string:
strcpy(buffer, input);
Be certain buffer is adequate in size.
Compares not accounting for '\n' that was read.
Lop off potential '\n'
fgets(input, sizeof(input), stdin);
// add
input[strcspn(input, "\n")] = '\0';
Buffer too small
buffer[] needs to hold 20 characters, '\n' and '\0'.
// char input[20];
char input[20 + 1 + 1];
Advanced
fgets() could return NULL which indicates stdin is closed.
User may enter too much text, good to detect that
#define INPUT_N 20
// extra \n \0
char input[INPUT_N + 1 + 1 + 1]; // I'd just go with INPUT_N*2
if (fgets(input, sizeof(input), stdin) == NULL) {
fprintf(stderr, "Input closed\n");
return EXIT_FAILURE;
}
size_t len = strlen(input);
if (len > 0 && input[len-1] == '\n') {
input[--len] = '\0'; // lop off \n
}
if (len > INPUT_N) {
// exit or otherwise cope with too much data
fprintf(stderr, "Excessive long input\n");
return EXIT_FAILURE;
}
...
sizeof is not a function that returning length of char-array. This is the keyword that returning a count of bytes which needed to allocation into memory any types and structures. Use strlen instead.
Try to print sizeof(char) and you will understand
Hi i am new to C and i am trying to use the Character array type below to captures input from users. How do i prevent or escape numerical characters. I just want only strings to be captured.
char str_input[105];
In have tried
scanf("%[^\n]s",str_input);
scanf("%[^\n]",str_input);
scanf("%[^0-9]",str_input);
scanf("%[A-Zaz-z]",str_input);
str_input = fgetc(stdin);
None of the above worked for me.
Input
2
hacker
Expected Output
Hce akr
int main() {
char *str_input;
size_t bufsize = 108;
size_t characters;
str_input = (char *)malloc(bufsize * sizeof(char));
if (str_input == NULL)
{
perror("Unable to allocate buffer");
exit(1);
}
characters = getline(&str_input,&bufsize,stdin);
printf("%zu characters were read.\n",characters);
int i;
int len = 0;
for (i = 0, len = strlen(str_input); i<=len; i++) {
i%2==0? printf("%c",str_input[i]): 'b';
}
printf(" ");
for (i = 0, len = strlen(str_input); i<=len; i++) {
i%2!=0? printf("%c",str_input[i]): 'b';
}
return 0;
}
Error
solution.c: In function ‘main’:
solution.c:21:5: warning: implicit declaration of function ‘getline’ [-Wimplicit-function-declaration]
characters = getline(&str_input,&bufsize,stdin);
Since your buffer has limited size, then using fgets(3) is fine. fgets() returns NULL on failure to read a line, and appends a newline character at the end of the buffer.
In terms of preventing numerical characters from being in your buffer, you can simply create another buffer, and only add non-numerical characters to it. You could just delete the numerical characters from your original buffer, but this can be a tedious procedure if you are still grasping the basics of C. Another method would be just to read single character input with getchar(3), which would allow you assess each character and simply ignore numbers. THis method is by far the easiest to implement.
Since you asked for an example of using fgets(), here is some example code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define INPUTSIZE 108
int main(void) {
char str_input[INPUTSIZE], characters[INPUTSIZE];
size_t slen, char_count = 0;
printf("Enter input:\n");
if (fgets(str_input, INPUTSIZE, stdin) != NULL) {
/* removing newline from fgets() */
slen = strlen(str_input);
if (slen > 0 && str_input[slen-1] == '\n') {
str_input[slen-1] = '\0';
} else {
fprintf(stderr, "Number of characters entered exceeds buffer size\n");
exit(EXIT_FAILURE);
}
/* checking if string is valid */
if (*str_input == '\0') {
fprintf(stderr, "No input found\n");
exit(EXIT_FAILURE);
}
printf("Buffer: %s\n", str_input);
/* only adding non-numbers */
for (size_t i = 0; str_input[i] != '\0'; i++) {
if (!isdigit(str_input[i])) {
characters[char_count++] = str_input[i];
}
}
/* terminating buffer */
characters[char_count] = '\0';
printf("New buffer without numbers: %s\n", characters);
}
return 0;
}
Example input:
Enter input:
2ttt4y24t4t3t2g
Output:
Buffer: 2ttt4y24t4t3t2g
New buffer without numbers: tttytttg
Update:
You could just use this even simpler approach of ignoring non-number characters:
char str_input[INPUTSIZE];
int ch;
size_t char_count = 0;
while ((ch = getchar()) != EOF && ch != '\n') {
if (!isdigit(ch)) {
if (char_count < sizeof(str_input)) {
str_input[char_count++] = ch;
}
}
}
str_input[char_count] = '\0';
If you're using Linux, I would use the getline() function to get a whole line of text, then verify it. If it is not valid input, I would in a loop ask the user to enter a line of text again and again until you the input is acceptable.
If not using Linux, well, your best bet is probably to reimplement getline(). You can also use fgets() if you find a limited-size buffer acceptable. I don't find limited-size buffers acceptable, so that's why I prefer getline().
getline() is used according to the way explained in its man page: http://man7.org/linux/man-pages/man3/getdelim.3.html
Basically, your loop should be something similar to:
char *buf = NULL;
size_t bufsiz = 0;
while (1)
{
if (getline(&buf, &bufsiz, stdin) < 0)
{
handle_error();
}
if (is_valid(buf))
{
break;
}
printf("Error, please re-enter input\n");
}
use_buffer(buf);
free(buf);
Well that's not possible. Numbers are string too. But you can set loop to look for numbers and print error. like this :
char *str = "ab234cid20kd", *p = str;
while (*p) { // While there are more characters to process...
if (isdigit(*p)) { // Upon finding a digit, ...
printf("Numbers are forbidden");
return 0;
} else {
p++;
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
This code does reverse and put result in file, but not fully correct.
Like, some issues with detecting line breaker or sth. Here's an example:
Source:
This is a line.
This is another line.
Quick brown fox jumps over a lazy dog!
Result:
(blank line)
.enil a si sihT
.enil rehtona si sihT!god yzal a revo spmuj xof nworb kciuQ
#include <stdio.h>
#include <string.h>
char *reverse (char *str)
{
char *begin, *end, c;
if (!str || !(*str))
return NULL;
for (begin=str, end=str+strlen(str)-1; begin<end; begin++, end--)
{
c=*begin;
*begin=*end;
*end=c;
}
begin=str+strlen(str)+1; *begin='\0'; //??
return str;
}
void main(void)
{
char line[1000];
FILE *fsrc, *frslt;
fsrc=fopen("source.txt", "r");
if (fsrc==NULL) return;
frslt=fopen("result.txt", "w");
while (!feof(fsrc))
{
fgets (line, 1000, fsrc);
fputs (reverse(line), frslt);
}
fclose(fsrc);
fclose(frslt);
}
A couple of comments/nitpicks, which may or may not solve your problem :)
if (!str || !(*str))
return NULL;
Don't do that. Don't return NULL on empty strings, fputs() will barf. In my experience, it's better to a) assert that the str pointer is non-null, b) return the empty string.
begin=str+strlen(str)+1; *begin='\0'; //??
There should be no need to terminate the string, since it's already terminated.
void main(void)
Nah, main() returns an int.
while (!feof(fsrc))
This won't work. You need to do some IO before you can test for feof()/ferror(). IMHO it's better to simply loop on fgets().
while (fgets(line, sizeof line, fsrc) {
...
}
It may be a good idea to drop the input and output files, and simply read from stdin and write to stdout, at least while testing. The functionality you're trying to implement is already available in a UNIX shell (man rev). Using stdin/stdout makes it easier to test and compare results with the results from rev.
Also, keep in mind that fgets() won't remove the \n from the string. input like "foo\n" becomes "\noof", which is probably not what you want.
Here's a snippet which illustrates my comments in code. It doesn't solve all problems, but should be sufficient to get you going.
#include <stdio.h>
#include <string.h>
#include <assert.h>
void reverse(char *str)
{
char *begin, *end, c;
size_t n;
assert(str != NULL);
n = strlen(str);
if (n == 0)
return;
for (begin = str, end = str + n - 1; begin < end; begin++, end--) {
c = *begin;
*begin = *end;
*end = c;
}
}
int main(void)
{
char line[1000];
while (fgets(line, sizeof line, stdin)) {
reverse(line);
fputs(line, stdout);
}
}
HTH
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I'm having some issues with this code and would mind to get a little help. This function reads from file to the dynamically allocated memory
Thanks #JonathanLeffler for help - function indent works perfectly! But one more issue appeared: with function read_file, that reads from file to char array, that is later passed to the indent.
=========================================================================
//--------------- read_file valgrind validations --------------------
==396== 144 bytes in 1 blocks are definitely lost in loss record 62 of 66
==396== at 0x4C2AD10: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==396== by 0x401AC1: read_file (polisher.c:24)
==396== by 0x4025CE: test_indent (test_source.c:174)
==396== by 0x406BC7: srunner_run (in /tmc/test/test)
==396== by 0x402C67: tmc_run_tests (tmc-check.c:134)
==396== by 0x402902: main (test_source.c:235)
==396==
=====================================================
char *read_file(const char *filename)
{
FILE *f = fopen(filename, "r");
if(!f)
return NULL;
int n = 0, c = 0;
char *a = NULL;
c = fgetc(f);
while(c != EOF)
{
n++;
c = fgetc(f);
}
freopen(filename, "r", f);
a = calloc(n + 1, sizeof(char));
c = fgetc(f);
n = 0;
while(c != EOF)
{
a[n] = c;
n++;
c = fgetc(f);
}
a[n] = '\0';
fclose(f);
return a;
}
================================================================
START_TEST(test_indent)
{
char *str = read_file("testifile.c");
if (!str) str = read_file("test/testifile.c");
if (!str) {
fail("[M6.01.c] read_file(\"testifile.c\") returned NULL");
}
char *res = indent(str, " ");
if (!res) {
free(str);
free(res);
fail("[M6.01.c] indent(\"testifile.c\") returned NULL");
}
char buf[OUTPUTLEN];
if (mycompare_new(res, ref61c, buf, OUTPUTLEN)) {
free(res);
free(str);
fail("[M6.01.c] Invalid string from indent(\"testifile.c\"): %s", buf);
}
free(str);
free(res);
test_complete();
}
END_TEST
Your basic problem is that the code for adding a single character to the output buffer doesn't check whether there's space for the extra character, and there might not be. You can tickle the bug quicker by using a longer indent (e.g. " /* Look Ma! */ ", which is 16 characters).
Where you currently have:
continue;
}
dest[dest_offset++] = c;
input++;
}
the brute force and carelessness solution adds:
continue;
}
if (dest_offset >= dest_len)
{
printf("XX: DO = %zu, DL = %zu, PL = %zu, LV = %zu\n", dest_offset, dest_len, pad_len, pad_level);
putchar('#');fflush(0);
char *ptr = realloc(dest, dest_len * 2);
if(!ptr)
{
free(dest);
return NULL;
}
dest_len *= 2;
dest = ptr;
}
putchar('.');fflush(0);
dest[dest_offset++] = c;
input++;
}
Oh, and I left some of the debug code I ended up using on display. I added quite a lot of vaguely similar printing code. An assertion at the top of the loop helped, too: assert(dest_offset <= dest_len);. When that went firing, things became clearer (but it took me a while to find out why it was firing). I also butchered the test in the newline handling code to:
if (dest_offset >= dest_len || (pad_len * pad_level + 1) >= (dest_len - dest_offset))
{
printf("YY: DO = %zu, DL = %zu, PL = %zu, LV = %zu\n", dest_offset, dest_len, pad_len, pad_level);
putchar('#');fflush(0);
char *ptr = realloc(dest, dest_len * 2);
if(!ptr)
{
free(dest);
return NULL;
}
dest_len *= 2;
dest = ptr;
}
but that realloc() never fired, which was one of the surprises.
I think you need a function to add one character to your output buffer, and you need to wrap up the output buffer control into a structure (struct Buffer { char *buffer; size_t maxlen; size_t curlen; } or thereabouts), and you have that one function deal with (re)allocating space as needed. That will avoid the glaring repeat of the 'brute force and carelessness' solution. You can make it a static inline function if you like — the compiler might avoid some overhead that way without compromising the readability of your code. There's also a nasty repeat with the two loops to add multiples of the indent to the buffer. That would be best treated with another function, of course — but it would be different from the 'add one char' in that you can sensibly check for enough space and do the reallocation once. Or write the function to take a length and pointer to a buffer that is not null terminated (so a single character has length 1 and the padding string has length pad_len) and a single function can do the whole lot — probably a better solution. I'd still package the controls into a structure and let the compiler optimize.
Test main():
int main(void)
{
char data[] = "#include <stdio.h>\nint main(void)\n{\nputs(\"Hello World!\\n\");\nreturn 0;\n}\n";
printf("Before: [[%s]]\n", data);
fflush(0);
char *reformatted = indent(data, " /* Look Ma! */ ");
printf("Indent: -complete-\n");
fflush(0);
printf("Source: [[%s]]\n", data);
fflush(0);
printf("Target: [[%s]]\n", reformatted);
free(reformatted);
return 0;
}