C: Unknow size input with scanf() - c

I'm trying to make a simple program where you put some text in it and it write back what you just wrote.
For example if I write "Hello World", the program should write me back "Hello World"
How I think it should work is like that :
loop to check if the current character is '\0'
if not print the current character and reallocate 1 more byte of memory
else stop the loop
So it's looks like an easy thing to do but my attempt is not working correctly, for example if you put only a few characters it is going to write you back with no problem but with longer string.. it is not working at all.
I know it is possible using fgets(), but I would like to understand why my version with scanf() isn't working.
(my code)
#include <stdio.h>
#include <stdlib.h>
int main(void){
int mem = 2;
char * str = malloc(mem);
scanf("%s", str);
while (*str != '\0') {
printf("%c", *str);
realloc(str, mem++);
str++;
}
free(str);
return 0;
}
edit : I was thinking that I only did a small mistake but, after reading the comments it looks like there is a lot of things that I did wrong in this tiny program. I'm going make sure that I better understand how C work and retry to do this program later. Thanks for the help!

Your program could be much more simple
#include <stdio.h>
int main() {
char c;
while( scanf("%c", &c) == 1 ) {
printf("%c", c);
}
return 0;
}

If you're going to use scanf for this, you shouldn't use "%s". (You should never use "%s" without a field width, since this will potentially overflow a buffer. Using "%s" is no better that gets().) If you are going to use a variant of "%s", you need to understand that it will ignore whitespace. The following does almost what you want, except for the whitespace issue. If you want to handle whitespace with precision, you cannot use "%s".
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
void * xrealloc(void *buf, size_t num, size_t siz, void *endvp);
int
main(void)
{
size_t cap = 2;
char *end = NULL;
char *str = xrealloc(NULL, cap, sizeof *str, &end);
/*
* Read 1 char at a time, discarding whitespace. This should
* be done with getchar(). If using scanf, a single char
* should be read with "%c". We use "%1s" here only
* because the question is specifically about `%s`.
* Note that %1s will allow scanf to write up to 2 characters into
* *end, so we need to ensure there is space for the terminator.
*/
while( 1 == scanf("%1s", end++) ){
while( end > str + cap - 2 ){
str = xrealloc(str, cap *= 2, sizeof *str, &end);
}
}
fputs(str, stdout);
free(str);
return 0;
}
void *
xrealloc(void *buf, size_t num, size_t siz, void *endvp)
{
char **endp = endvp;
char *b = buf;
ptrdiff_t offset = b && endp && *endp ? *endp - b : 0;
b = realloc(b, num * siz);
if( b == NULL ){
perror("realloc");
exit(EXIT_FAILURE);
}
if( endp != NULL ){
*endp = b + offset;
}
return b;
}

Reading functions' manuals and searching for similar questions is a great method to get things clearer, and undestand the problem you are facing better :)
Try looking at this question: Reading input of unknown length, and particularly at this answer that uses scanf: scanf answer (I did not verify if that works, but it teaches you another method you can use).

Related

Unable to find error in code that write every word of a string in a new line

I am writing a code that takes a string as input and prints every word in the string in a newline.
I am using pointer arithmetic for this purpose
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
while (*s != '\0') {
if (*s == ' ') {
printf("\n");
} else {
printf("%s", s);
}
s++;
}
return 0;
}
Input:
i am a beginner. \n
Output:
i am a beginner \n
am a beginnerm a beginner \n
a beginner \n
beginnereginnerginnerinnernnernererr
Instead of %s you need %c to print a single character. Besides that, you don't need to free the memory you get from malloc since realloc takes care of that, but you have to free the memory you got from realloc. Yes, the OS will clean up after you, but it is best to release the resources you acquired. In order to do the free we are going to not change the value of s, instead we are going to copy it. Here is the fixed version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char* s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
char* p = s = realloc(s, strlen(s) + 1);
while (*p != '\0') {
if (*p == ' ') {
printf("\n");
} else {
printf("%c", *p);
}
++p;
}
free(s);
return 0;
}
Input:
My awesome input
Output:
My
awesome
input
A few points for you to consider. If the user adds multiple space characters in between words or adds something like '\t', your program doesn't handle the case correctly.
I would say its not very logical to reinvent the wheel unless you need some extra functionality or portability. Same can be done more reliably like:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
char *to_free = s = realloc(s, strlen(s) + 1);
char *word;
while ((word = strsep(&s, " \t")) != NULL)
printf("%s\n", word);
free(to_free);
return 0;
}
This also allows you to keep track of tabs as well as spaces(as you are considering words). Notice the argument passed to strsep, its a space and a tab. You could easily separate words using ,, . etc as well by just adding these delimeters to the strsep argument.
Also it is a good practice to free the memory you allocated.
if you use printf with "%s" it prints out the entire string all the way to \0.
that's why you see the entire sentence in every line (minus a few characters from the start).
the way you used pointers in this code, I'm guessing you're trying print out individual characters, so just switch "%s" with "%c"

Which is the best way in this case to extract the substring from a string which is inputted by the user in C

Let's say I have the following string stored in char *m;
char *m = "K: someword\r\n";
The m will be inputed by the user so the user will write in the console:
K: someword\r\n
The someword can have different length, while K: \r\n will always be the same.
Now my question is, which is the best way after I read this input to extract someword from it and save it into a new char* variable?
Use sscanf() like this:
#include <stdio.h>
int main (void)
{
char buffer [50], k, return_car, new_line;
int n = sscanf ("K: someword\r\n", "%c: %s%c%c", &k, buffer, &return_car, &new_line);
printf ("The word is \"%s\". sscanf() read %d items.\n", buffer, n);
return 0;
}
Output:
The word is "someword". sscanf() read 4 items
Since both the substrings we aren't interested in ("K: " and "\r\n") are of fixed length, you can do this:
char *s;
size_t len = strlen(m);
s = malloc(len);
strcpy(s, m + 3);
s[len - 4] = 0;
printf("%s\n", s);
free(s);
Note that I declared a new char * variable to copy to since m is in read-only memory, and that robust code would handle the case where malloc failed and returned NULL.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char *m = "K: someword\r\n";
const size_t someword_len = strlen(&m[3]);
char *someword = malloc(someword_len);
if (someword == NULL) { fprintf(stderr, "Malloc error\n"); abort(); }
memcpy(someword, &m[3], someword_len - 2);
someword[someword_len - 1] = '\0';
puts(someword);
free(someword);
}
You assume that string m always starts with "K: " (that's 3 characters) and ends with "\r\n" (that's two characters).
I believe strlen(m) will be faster then strchr(m, '\r') or strrchr(m, '\r') on most platforms
After you have the length of the string, using memcpy instead of strcpy will be faster.
Remember to null terminate your string
Remember to handle errors.

Manipulation array in function - c - Segmentation fault

So I started to learn how to code a few weeks ago, and this site helped me so much, thank you for that. But this time I got stuck and canĀ“t really figure out why...Hope you can help me.
Basically I have a function prototype I have to use in my program and I have my troubles with it. The function should receive a string and then only copy every second char of that string and return the result...
This is what I've got so far:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define max_size 1000
char * everySecondChar(char * dest, char * input);
int main() {
char inputstr[max_size] = {0};
char *input[max_size] = {0};
char *dest[max_size] = {0};
char temp[max_size] = {0};
int i = 0;
while (fgets(inputstr, max_size, stdin) != NULL)
{
input[i] = strndup(inputstr, max_size);
strcat(temp,inputstr);
i++;
}
input[0] = strndup(temp, max_size);
printf("Inputted text:\n%s", *input);
printf("\n");
printf("\n");
printf("Resulting string:\n");
everySecondChar(*dest, *input);
printf("%s", *dest);
return 0;
}
char * everySecondChar(char * dest, char * input)
{
int i = 0;
for(i = 0; i < max_size; i+=2) {
strcat(dest,input);
}
return dest;
}
I know this is probably a 1-min challenge for the most of you, but I am having my troubles whenever I see those nasty * in a function prototype :(
Congrats on getting started with programming!
To your question: there's quite a few things that could be addressed, but since there seems to be some more basic confusion and misunderstanding, I'll address what makes sense given the context of your issue.
First, you're using strcat which concatenates strings (e.g. adds to the string), when you just need simple character assignment.
Next, you have a lot of pointers to arrays and there seems to be some confusion regarding pointers; in your main function, you don't need all of the temporary variables to do what you're wanting.
You could have simply:
char inputstr[MAX_SIZE] = {0};
char dest[MAX_SIZE] = {0};
You could have less (realistically) but we'll stick with the basics for now.
Next, you're looping to get user input:
while (fgets(inputstr, max_size, stdin) != NULL)
{
input[i] = strndup(inputstr, max_size);
strcat(temp,inputstr);
i++;
}
Here, you don't check if i exceeds max_size which your input variable has been allocated for; if i exceeds max_size when you go to assign input[i] to the memory location returned by strndup (which calls malloc), you are writing beyond your memory bounds, which is also known as a buffer overflow. This is potentially where your segmentation fault is happening. You could also have some issues when you do strcat(temp,inputstr); since strcat:
Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
If you're simply just trying to get what the user entered, and print every 2nd character with your function, you don't need to loop:
if (fgets(inputstr, MAX_SIZE, stdin) != NULL) {
everySecondChar(dest, inputstr);
printf("Inputted text:\n%s\n\nResulting string:\n%s\n", inputstr, dest);
}
Lastly, in your everySecondChar function, you're using strcat again when all you need to do is simple assignment (which does a 'copy'):
char * everySecondChar(char * dest, char * input)
{
int i, j;
for(i = 0, j = 0; i < MAX_SIZE; ++i, ++j) {
if (input[i] == 0) break; // end if string?
dest[j] = input[i++];
}
return dest;
}
Putting all of it together, you get:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_SIZE 1000
char * everySecondChar(char * dest, char * input);
int main(void)
{
char inputstr[MAX_SIZE] = {0};
char dest[MAX_SIZE] = {0};
printf("Enter some text: ");
if (fgets(inputstr, MAX_SIZE, stdin) != NULL) {
everySecondChar(dest, inputstr);
printf("Inputted text:\n%s\n\nResulting string:\n%s\n", inputstr, dest);
}
return 0;
}
char * everySecondChar(char * dest, char * input)
{
int i, j;
for(i = 0, j = 0; i < MAX_SIZE; ++i, ++j) {
if (input[i] == 0) break; // end if string?
dest[j] = input[i++];
}
return dest;
}
That aside, I'll address some other things; typically if you have a constant value, like your max_size variable, it's considered "best practice" to capitalize the entire thing:
`#define MAX_SIZE 1000`
I am having my troubles whenever I see those nasty * in a function prototype :(
Those nasty *'s in your function prototype (and variable declarations) are known as a pointer qualifier; it indicates that the type of the variable is a pointer to the type specified. A pointer isn't something to be scared of, you're learning C, it's highly important you understand what a pointer is and it's utility.
I won't dive into all of the specificities of pointers, aliases, etc. etc. since that is beyond the scope of this Q&A, but WikiBooks has a great intro and explanation covering a lot of those concepts.
Hope that can help!

printing a paragraph using putchar()

Consider the following code:-
#include"stdio.h"
void main()
{
char ch;
while((ch=getchar())!=EOF)
{
putchar(ch);
}
}
Whatever input I give to (as a sentence) it is repeated after I hit return key. What should I do if I want to get the entire paragraph at the end ? Can this be done using putchar() because putchar() can be used only to return a single character.
This won't work, since EOF doesn't fit in a char. Note that the proper return type of getchar() is int. See for instance this manual page.
If you want to read in a whole line at once, you can use fgets() into a character buffer for instance. I'm not sure I'm understanding exactly what you want to achieve, though.
EOF should be used when reading from files as the files end with a special EOF(end of file) character.You need to use any sentinel here to represent end of input.
this program makes a very little sense and I cant picture the use of this anywhere. So rethink about the requirements and change the logic accordingly.
may this code help you
char *buffer;
int i = 255;
buffer = (char *)malloc(i*sizeof(char));
*buffer = getchar();
while ( *buffer != '?' )
{
buffer++;
*buffer = getchar();
}
Try to store your char into a buffer and the when quit the while loop print the buffer. Try this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int c;
char *buf = calloc(1,sizeof(char));
int len;
while ((c=getchar())!=EOF) {
len = strlen(buf);
buf = realloc(buf, len+1);
buf[len] = (char) c;
buf[len + 1] = '\0';
}
printf("%s",buf);
}
If you want to get entire paragraph at end, you should store the input in a buffer while EOF reaches. then print content of buffer in a loop. Also as Mr. Unwind's answer says make, ch variable a int, char is wrong!
#include"stdio.h"
#define SIZE 1024
void main()
{
int buffer[SIZE]
int ch;
int i=0;
// Read and store in a buffer
while((ch=getchar())!=EOF)
{
buffer[i] = ch;
i++;
}
buffer[i] = EOF;
// now print using putchar(ch);
i = 0;
while((ch = buffer[i]) !=EOF)
{
putchar(ch);
i++;
}
}
cose all we did in console/terminal - until we dont hit Enter/Return/^J/^M shell not send line to our program
u can get paragraph(more then 1 line) by copy and paste some lines so terminal|console program show 1st u pasted then repeated - output of u program

Help with custom getline() function

Can anyone explain to me why this isn't working?
#include <stdio.h>
#include <stdlib.h>
char *getline(int lim)
{
char c;
int i;
char *line;
line = malloc(sizeof(char) * lim);
i = 0;
while((c = getchar()) != '\n' && c != EOF && i < lim-1)
{
*line = c;
line++;
i++;
}
*line = '\0';
printf("%s", line);
return line;
}
I'm not worried about the return value right now - just the reason as to why printf("%s", line) isn't working.
Thanks!
EDIT: fixed to line = malloc(sizeof(char) * lim); but it is still not working.
Solution: the address of *line was being incremented throughout the function. When it was passed to printf(), *line pointed to '\0' because that's where its adress was incremented to. Using a temprorary pointer that stored the original address allocated by malloc() to *line and then passing that pointer into printf(), allowed for the function to walk up the pointer.
Because you are only allocating enough space for a single character in this line:
line = malloc(sizeof(char));
And that is getting filled with the \0 before your printf statement.
I'm guessing you want to change this line to:
/* Allocate enough room for 'lim' - 1 characters and a trailing \0 */
line = malloc(sizeof(char) * lim);
Or even better:
char *line, *tmp;
tmp = line = malloc(sizeof(char) * lim);
And then use tmp in all of your pointer math, this way line will still point to the start of your string.
And I know it's early in your development, but you'll want to make sure you free() the memory that you malloc().
Here is a working version of your function including my suggested changes:
#include <stdio.h>
#include <stdlib.h>
char *getline(int lim)
{
char c;
int i;
char *line, *tmp;
tmp = line = malloc(sizeof(char) * lim);
i = 0;
/* NOTE: 'i' is completely redundant as you can use 'tmp',
* 'line,' and 'lim' to determine if you are going to
* overflow your buffer */
while((c = getchar()) != '\n' && c != EOF && i < lim-1)
{
*tmp = c;
tmp++;
i++;
}
*tmp = '\0';
printf("%s", line);
return line;
}
It looks like you're printing a zero-length string.
*line = '\0';
printf("%s", line);
I presume that you want to store what line was originally (as returned from malloc) and print that.
Everyone has covered these points already, but here is the whole thing all put together:
Edit: Improved the code a little
#include <stdio.h>
#include <stdlib.h>
char *getline(int lim)
{
char *result = malloc(sizeof(char) * lim); // allocate result buffer
int i = 0;
char c;
char *line = result;
while((c = getchar()) != '\n' && c != EOF && i < lim-1)
{
*line = c;
line++;
i++;
}
*line = '\0';
printf("%s", result); // print the result
return result; // return the result buffer (remember to free() it later)
}
You seem to have allocated enough room for only one character. Did you mean the following instead:
line = malloc(lim * sizeof(char));
Also, you don't want to change line after reading each character. Use the following block for your while-loop instead:
*(line + i) = c;
i++;
And finally, to null-terminate the string, use:
*(line + i) = '\0';
Updated-it was a simple typo mistake,but you didn't have to vote me down on it
instead of
char *line= malloc(sizeof(char));
try
int space= //number of how many characters you need on the line
char *line= malloc(sizeof(char)*space);
sorry I meant
char *line= malloc( sizeof(char)*lim)
You're also overwriting memory you don't own. You're malloc'ing one character, setting *line to c, and then incrementing line and repeating.
You need to understand the concept of pointer, and how it's different from a buffer.
In your code, you treat "line" as pointer and buffer at the same time.
You are Making mistake on two points (but you can say same mistake or two ,its upto you). first your pointer should be incremented like
*(line+i) = c;
Due to this reason when you set the Null char at the end of loop you are actually saying the compiler to point the pointer to only this poistion.Hence the pointer is only pointing at Null String not the whole string. As it was constantly being moved in each step of the loop.
So when you tried to print that the pointer has nothing to print. So if you change your statement inside the loop for pointer and assign the value to an express address rather then actually moving the pointer then you problem will be solved.
Note. If you change that line then you also need to modify your Null terminator assignment like this;
*(line+limit) = '\0';

Resources