I'm trying to read the input sent through the serial monitor but scanf does nothing and i can't figure out how to get getchar to do the same thing.
Here's a piece of code that I've tried to use that does not work on the pico. It does work on my pc.
char *readInput() {
int i = 0;
char ch;
char *str = malloc(sizeof(char) * 1024);
while((ch = getchar()) != '\n' && ch != EOF) {
if (i < 1024) {
str[i++] = ch;
printf("%c\n", ch); // For debugging. Returns the correct character.
}
}
printf("%s\n", str); // For debugging. Returns nothing.
str[i] = '\0';
return str;
}
It looks like it just tries to read until it gets to the 1024th character.
Also I've read somewhere that scanf doesn't work on the Pico but some people say it works so i don't even know anymore.
malloc()'s result is discarded:
char *str = malloc(sizeof(char) * 1024);
malloc() returns a NULL pointer to indicate failure, which it can and does. Its return value should always be checked. If it returns NULL, subsequent operations would be dereferencing and writing to a NULL pointer.
Aside: sizeof (char) is defined to be 1, so you can leave that out.
char *str = malloc(1024);
/* Add */
if (!str) {
/* malloc() failed to allocate memory.
* Handle error here.
*/
}
Off-by-one error:
if (i < 1024)
doesn't leave room for the null-byte.
getchar() returns an int:
char ch;
while((ch = getchar()) != '\n' && ch != EOF)
If the integer value returned by getchar() is stored into a
variable of type char and then compared against the integer
constant EOF, the comparison may never succeed, because sign-
extension of a variable of type char on widening to integer is
implementation-defined.
Undefined behaviour:
printf("%s\n", str); // For debugging. Returns nothing.
The %s format specifier expects a string. str is not a string. The call to printf() would invoke undefined behaviour.
Move
str[i] = '\0';
before the call to printf().
Writing to out of bounds memory:
str[i] = '\0';
The value of i is 1024 when the while loop exits. You only allocated memory for 1023 characters.
Minor:
char *readInput()
indicates that readInput takes an unspecified number and type of arguments.
char *readInput (void)
doesn't.
Related
I get very unexpected output from quite simple code
char ch = getchar(), word[100], *p = word;
while (ch != '\n') {
*(p++) = ch;
ch = getchar();
}
puts(word);
output of any 17 character input is appended by "time" like
12345678901234567time
if exceeds "time" is overwritten like
1234567890123456789me
Am I doing something wrong?
puts expects a pointer to string. And a string needs to have a terminating null character - \0 - to signify where the string ends.
But in your case, you did not write the \0 at the end to signify that the string ends there.
You need to do:
char ch = getchar(), word[100], *p = word;
/* Also check that you are not writing more than 100 chars */
int i = 1;
while(ch != '\n' && i++ < 100){
*(p++) = ch;
ch = getchar();
}
*p = '\0'; /* write the terminaring null character */
puts(word);
Before, when you were not writing the terminating null character you could not expect anything determinate to print. It could also have been 12345678901234567AnyOtherWord or something.
There are multiple issues in your code:
You do not null terminate the string you pass to puts(), invoking undefined behavior... in your case, whatever characters happen to be present in word after the last one read from stdin are printed after these and until (hopefully) a '\0' byte is finally found in memory.
You read a byte from stdin into a char variable: this does not allow you to check for EOF, and indeed you do not.
If you read a long line, you will write bytes beyond the end if the word array, invoking undefined behavior. If the end of file is encountered before a '\n' is read from stdin, you will definitely write beyond the end of the buffer... Try for example giving an empty file as input for your program.
Here is a corrected version:
char word[100];
char *p = word;
int ch;
while ((ch = getchar()) != EOF && ch != '\n') {
/* check for long line: in this case, we truncate the line */
if (p < word + sizeof(word) - 1) {
*p++ = ch;
}
}
*p = '\0';
puts(word);
I have to create a C function that returns a line read from a file descriptor. I have to define a macro READ_SIZE (that can be editable). This READ_SIZE indicates the number of characters to read at each call of read(). The number can only be positive.
I also have to use one or several static variables to save the characters that were read but not sent back to the calling function. One .C file (5 functions max, 25 lines max per function) and one .h file only.
My function Get_Next_Line shall return its return without the '\n'. If there is nothing more to read on the file descriptor, or if an error occur while reading, the function returns NULL.
Here is the prototype of the function:
char *get_next_line(const int fd)
FUNCTIONS ALLOWED: malloc, free, read, write (to use with my_putchar, my_putstr, etc).
Here is what I have, but it doesn't work. It does an infinite loop I am trying to know why.
char *my_strcat(char *str1, char *str2)
{
int i;
int j;
int s;
char *strfinal;
i = 0;
j = 0;
s = 0;
if ((strfinal = malloc(sizeof(char) * (my_strlen(str1) + my_strlen(str2)
+ 1))) == NULL)
return (NULL);
while (str1[i] != '\0')
{
strfinal[j] = str1[i];
i++;
j++;
}
while (str2[s] != '\0')
{
strfinal[j] = str2[s];
s++;
j++;
}
free(str1);
strfinal[j] = '\0';
return (strfinal);
}
char *get_next_line(const int fd)
{
int n;
int i;
char *str_to_return;
static char buff[READ_SIZE] = {'\0'};
n = 1;
i = 0;
str_to_return = NULL;
while (n)
{
if (i == 0 && buff == '\0')
{
if ((read(fd, buff, READ_SIZE)) <= 0)
return(str_to_return);
if (i == READ_SIZE - 1 || buff[i] == '\n')
{
n = 0;
str_to_return = my_strcat(buff, str_to_return);
i = -1;
}
}
i++;
}
printf("%s\n", str_to_return);
return (str_to_return);
}
in this code:
while (str1[i] != '\0')
{
strfinal[j] = str1[i];
i++;
j++;
}
what guarantee do you have that there will be the null character \0 somewhere in str1[] ???
same goes for the str2 while loop.
If no null character is encountered, then there will be an infinite loop there.
verify the functions you are using to populate characters into memory under str1[] and str2[] include the null character. Since you are only using the read() function prior then that answer is no.
The problem with your two while loops for str1[] and str2[] is that you are relying on the null character to already be there in memory. And that then begs the question, who put that data there in memory and were they given a requirement to terminate the character data with a null character?
you therefore need to somehow place a control over any loop you write so as not get caught in an infinite loop condition; in this case maybe use a counter and after so many advances of the i to access str1[i] then stop, because you have yet to see a null character.
for example, the fgets() function will read so many characters from a FILE stream into an array, and always terminate it with the null character.
if (i == 0 && buff == '\0')
is always false because your definition of buff is
static char buff[READ_SIZE] = {'\0'};
You are attempting to test if buff is empty when i is 0. However as a char pointer, buff is an address and is never 0. You mean to make the if
if (i == 0 && buff[0] == '\0')
in order to check if the first character is the Null character.
However, once i is incremented, then it always fails even if you test against
if (i == 0 && buff[i] == '\0')
in order to find the NULL character within the buffer. Since you enter the while with i = 0 and are checking if buff is empty, you do not need the while.
If you want to just fill the buffer and keep reading until it is full, you need a different type of test. You also need a way of checking if you need to exit the while loop if the if fails (put in an else to determine what to do).
You also do not need to check each character in buff against '\0' because your code has always insured that it ends with one (even for initialization). Thus, strlen(buff) would be valid.
Another point is that when you call mystrcat() you have already verified that buffer is empty.
Also, since the second string in the call is what you read in, then the mystrcat() will not always have a '\0' at the end of str2 (though you are guaranteeing that buff (str1) will). You should call it with the number of characters in str2 to use.
i am trying to code a C function which returns a line read from the input as a char* . I am on Windows and i test my program in the command line by giving files as input and output of my program like this:
cl program.c
program < test_in.txt > test_out.txt
This is my (not working) function:
char* getLine(void)
{
char* result = "";
int i, c;
i = 1;
while((c = getchar()) != EOF)
{
*result++ = c;
i++;
if(c == '\n')
return result - i;
}
return result - i;
}
I was expecting it to work because i previously wrote:
char* getString(char* string)
{
//char* result = string; // the following code achieve this.
char* result = "";
int i;
for(i = 1; *result++ = *string++; i++);
return result - i;
}
And these lines of code have a correct behaviour.
Even if every answers will be appreciated, i would be really thankfull
if any of you could explain me why my getString() function works while my getLine() function doesn't.
Your function does not allocate enough space for the string being read. The variable char* result = "" defines a char pointer to a string literal ("", empty string), and you store some arbitrary number of characters into the location pointed to by result.
char* getLine(void)
{
char* result = ""; //you need space to store input
int i, c;
i = 1;
while((c = getchar()) != EOF)
{
*result++ = c; //you should check space
i++;
if(c == '\n')
return result - i; //you should null-terminate
}
return result - i; //you should null-terminate
}
You need to allocate space for your string, which is challenging because you don't know how much space you are going to need a priori. So you need to decide whether to limit how much you read (ala fgets), or dynamically reallocate space as you read more. Also, how to you indicate that you have finished input (reached EOF)?
The following alternative assumes dynamic reallocation is your chosen strategy.
char* getLine(void)
{
int ch; int size=100; size_t pos=0;
char* result = malloc(size*sizeof(char*));
while( (ch=getchar()) != EOF )
{
*result++ = ch;
if( ++pos >= size ) {
realloc(result,size+=100);
//or,realloc(result,size*=2);
if(!result) exit(1); //realloc failed
}
if( c=='\n' ) break;
}
*result = '\0'; //null-terminate
return result - pos;
}
When you are done with the string returned from the above function, please remember to free() the allocated space.
This alternative assumes you provide a buffer to store the string (and specifies the size of the buffer).
char* getLine(char* buffer, size_t size)
{
int ch;
char* result = buffer;
size_t pos=0;
while( (ch=getchar()) != EOF )
{
*result++ = ch;
if( ++pos >= size ) break; //full
if( c=='\n' ) break;
}
*result = '\0'; //null-terminate
return buffer;
}
Both avoid the subtle interaction between detecting EOF, and having enough space to store a character read. The solution is to buffer a character if you read and there is not enough room, and then inject that on a subsequent read. You will also need to null-ter
Both functions have undefined behaviour since you are modifying string literals. It just seems to work in one case. Basically, result needs to point to memory that can be legally accessed, which is not the case in either of the snippets.
On the same subject, you might find this useful: What Every C Programmer Should Know About Undefined Behavior.
Think of it this way.
When you say
char* result = "";
you are setting up a pointer 'result' to point to a 1-byte null terminated string (just the null). Since it is a local variable it will be allocated on the stack.
Then when you say
*result++ = c;
you are storing that value 'c' in to that address + 1.
So, where are you putting it?
Well, most stacks are to-down; so they grow toward lower addresses; so, you are probably writing over what is already on the stack (the return address for whatever called this, all the registers it needs restore and all sorts of important stuff).
That is why you have to be very careful with pointers.
When you expect to return a string from a function, you have two options (1) provide a string to the function with adequate space to hold the string (including the null-terminating character), or (2) dynamically allocate memory for the string within the function and return a pointer. Within your function you must also have a way to insure your are not writing beyond the end of the space available and you are leaving room for the null-terminating character. That requires passing a maximum size if you are providing the array to the function, and keeping count of the characters read.
Putting that together, you could do something similar to:
#include <stdio.h>
#define MAXC 256
char* getLine (char *s, int max)
{
int i = 0, c = 0;
char *p = s;
while (i + 1 < max && (c = getchar()) != '\n' && c != EOF) {
*p++ = c;
i++;
}
*p = 0;
return s;
}
int main (void) {
char buf[MAXC] = {0};
printf ("\ninput : ");
getLine (buf, MAXC);
printf ("output: %s\n\n", buf);
return 0;
}
Example/Output
$ ./bin/getLine
input : A quick brown fox jumps over the lazy dog.
output: A quick brown fox jumps over the lazy dog.
There is a file called prog1.txt that is being read into my program. To execute, I use the name of the file and a '<' symbol to read in the file. (./a.out < prog1.txt). When i read it in however, i immediately receive a segmentation fault. Here is what I have written that is giving this issue:
char *strPtr;
while(((*strPtr = getchar()) != EOF) && (*strPtr != '\n')) {
strPtr++;
}
I have researched other questions, but I can't find a problem whose solution is usable for this. What is causing the segmentation fault??
You have a pointer char* strPtr, but it might not point to anything that you can use. You'll need to allocate some memory. char* strPtr = malloc(numChars); You should also free it after you're finished with the allocated memory: free(strPtr);
You'll need to set a maximum number of characters you can read in. In this case I use numChars.
Creating a pointer does not create something for it to point at. When using a pointer (or array syntax) it is the programmer's responsibility to ensure things are set up correctly.
getchar() returns int, and EOF is a value that cannot be represented using a char. Comparing any value of type char with EOF will therefore always fail.
You need to deal with both these concerns. You are not.
For example;
char *strPtr = malloc(10);
int length = 0;
if (strPtr != NULL)
{
int achar;
while(length < 10 && (achar = getchar()) != EOF && achar != '\n')
{
strPtr[length] = (char)achar;
++length;
}
}
/* do whatever is needed with strPtr and length*/
free(strPtr);
The check that strPtr is not NULL is to ensure the malloc() call succeeded before trying to write to the allocated array.
length is being used to ensure the code does not write to strPtr past the allocated length.
achar is used to check for EOF before converting the value to a char (not after, as in your code).
Use an array
char strPtr[10];
int temp;
int i = 0;
while( i < 10 && ((temp = getchar()) != EOF) && (temp != '\n')) {
strPtr[i] = temp;
i++;
}
I'm trying to get an expression from the user and put it in a dynamically created string. Here's the code:
char *get_exp() {
char *exp, *tmp = NULL;
size_t size = 0;
char c;
scanf("%c", &c);
while (c != EOF && c != '\n') {
tmp = realloc(exp, ++size * sizeof char);
if (tmp == NULL)
return NULL;
exp = tmp;
exp[size-1] = c;
scanf("%c", &c);
}
tmp = realloc(exp, size+1 * sizeof char);
size++;
exp = tmp;
exp[size] = '\0';
return exp;
}
However, the first character read is a newline char every time for some reason, so the while loop exits. I'm using XCode, may that be the cause of the problem?
No, XCode is not part of your problem (it is a poor workman who blames his tools).
You've not initialized exp, which is going to cause problems.
Your code to detect EOF is completely broken; you must test the return value of scanf() to detect EOF. You'd do better using getchar() with int c:
int c;
while ((c = getchar()) != EOF && c != '\n')
{
...
}
If you feel you must use scanf(), then you need to test each call to scanf():
char c;
while (scanf("%c", &c) == 1 && c != EOF)
{
...
}
You do check the result of realloc() in the loop; that's good. You don't check the result of realloc() after the loop (and you aren't shrinking your allocation); please check every time.
You should consider using a mechanism that allocates many bytes at a time, rather than one realloc() per character read; that is expensive.
Of course, if the goal is simply to read a line, then it would be simplest to use POSIX getline(), which handles all the allocation for you. Alternatively, you can use
fgets() to read the line. You might use a fixed buffer to collect the data, and then copy that to an appropriately sized dynamically allocated buffer. You would also allow for the possibility that the line is very long, so you'd check that you'd actually got the newline.
Here on Windows XP/cc, like Michael said, it works if exp is initialized to NULL.
Here's a fixed code, with comments explaining what is different from your code in the question:
char *get_exp()
{
// keep variables with narrowest scope possible
char *exp = NULL;
size_t size = 0;
// use a "forever" loop with break in the middle, to avoid code duplication
for(;;) {
// removed sizeof char, because that is defined to be 1 in C standard
char *tmp = realloc(exp, ++size);
if (tmp == NULL) {
// in your code, you did not free already reserved memory here
free(exp); // free(NULL) is allowed (does nothing)
return NULL;
}
exp = tmp;
// Using getchar instead of scanf to get EOF,
// type int required to have both all byte values, and EOF value.
// If you do use scanf, you should also check it's return value (read doc).
int ch = getchar();
if (ch == EOF) break; // eof (or error, use feof(stdin)/ferror(stdin) to check)
if (ch == '\n') break; // end of line
exp[size - 1] = ch; // implicit cast to char
}
if (exp) {
// If we got here, for loop above did break after reallocing buffer,
// but before storing anything to the new byte.
// Your code put the terminating '\0' to 1 byte beyond end of allocation.
exp[size-1] = '\0';
}
// else exp = strdup(""); // uncomment if you want to return empty string for empty line
return exp;
}