C string disappears along with newline - c

I'm new to C and stackoverflow, so pardon me if my question is silly or a duplicate.
So i tried to read some lines of string (and integers) from a .txt files and store it into an array of tuples. The strings read from the file seems to contain '\n' everytime, so i use strcspn() to remove it.
FILE* f = fopen("board.txt","r");
int x;
size_t size = 30;
char *buffer;
for (i=1;i<=32;i++)
{
buffer = (char *)malloc(size);
x = getline(&buffer,&size,f);
buffer[strcspn(buffer,"\n")] = 0;
A[i].name = buffer;
buffer = (char *)malloc(size);
x = getline(&buffer,&size,f);
buffer[strcspn(buffer,"\n")] = 0;
A[i].type = buffer;
buffer = (char *)malloc(size);
x = getline(&buffer,&size,f);
A[i].price = atoi(buffer);
}
for (i=1;i<=32;i++)
printf("%s ",A[i].name);
for (i=1;i<=32;i++)
printf("%s ",A[i].type);
However, when i tried the code above, the printf failed to print anything. But then when i tried to use \n in the printf ( printf("%s\n",A[i].type); ) it worked just fine. It seems like the strings completely disappear when i remove the "\n", and then come back only when i put '\n' as i print it.
Can someone explain what is wrong in the code? Or is it a library problem? Thank you in advance.
Edit : So to explain it a little further, i need those string (name and type) to be printed into 'boxes' to form a kind of board game, so i think bringing newline would cause a lot of trouble later on.

This is the correct behavior. The '\n' causes the OS to flush the buffer used for prints, so that it appears on stdout. Without a '\n' the OS isn't forced to write your print to stdout yet.

printf belongs to the Standard I/O library, it is a line buffered function. So when this function is called, it stores characters in a buffer and the only way to get the output (to stdout) is to flush with a newline character. This is the way it was designed so as to maintain a minimal number of system calls as possible.
Try eliminating this,
buffer[strcspn(buffer,"\n")] = 0;

Related

Have to hit enter twice with fgets() in C?

Good Morning, I'm having an issue with some C code where I am forced to hit enter twice each time input is entered if the length of the input is less than the size of 'guess'.
If the length of the input is longer than guess, I only hit enter once, and it functions normally.
I'm not sure what the issue is here, but I provided the function in question that I believe is the source of the problem along with the caller function and main just for context.
Output:
Guess a number: 5555555555
Invalid guess.
Guess a number: 55555555555
Invalid guess.
Guess a number: 555
Invalid guess.
Guess a number:
Invalid guess.
Guess a number: 5555
When I remove the line:
while((ch = getchar()) != '\n' && ch != EOF); // Flush the input buffer
and I extend past the size of the buffer, I receive this output:
Guess a number: 5555555555555555555555555555555555
Invalid guess.
Guess a number: Invalid guess.
Guess a number: Invalid guess.
Guess a number: Invalid guess.
Guess a number: Invalid guess.
Function in Question
char * get_input(char * guess)
{
print_message("guess"); // Prompt user to input a guess
fgets(guess, sizeof (guess), stdin);
if(feof(stdin))
{
printf("error");
exit(EXIT_FAILURE);
}
int ch = 0;
while((ch = getchar()) != '\n' && ch != EOF); // Flush the input buffer
guess[strlen(guess)-1] = '\0'; // Erase new line character
return guess;
}
Caller Function
int make_guess(int *v_guess_count)
{
int result = 0;
bool valid = false;
char guess[10] = {'\0'}; // Buffer to store the guess
do
{
get_input(guess); // Get the input
if(is_valid(guess)) // Check if the input is valid
{
valid = true;
*v_guess_count += 1;
}
}
while (! valid); // Keep asking for input until guess is valid
result = assign_value(guess); // Assign the guess
return result;
}
Main
int main(int argc, char * argv[])
{
int red = 0;
int white = 0;
int v_guess_count = 0;
int target = get_target();
bool game_won = false;
while(game_won == false)
{
red, white = 0; // Reset to zero after each guess
int guess = make_guess(&v_guess_count); // Make a guess. If it's valid, assign it.
printf("guess is: %d\n", guess);
compare(guess, target, &red, &white); // Check the guess with the target number.
print_hints(&red, &white);
if (red == 4)
{
game_won = true;
}
}
printf("You win! It took you %d guesses.\n", v_guess_count);
return 0;
}
You have two somewhat-related problems.
One. In your function
char * get_input(char * guess)
your line
fgets(guess, sizeof (guess), stdin);
does not do what you think it does. You want to tell fgets how big the buffer is, that is, how much memory is pointed to by guess for fgets to read into. But in function get_input, parameter guess is a pointer, so sizeof(guess) is going to be the size of that pointer, not the size of the array it points to. That is, you're going to get a size of probably 4 or 8, not the 10 that array guess up in make_guess is declared as.
To fix this, change your input function to
char * get_input(char * guess, int guess_size)
and change the call in make_guess to
get_input(guess, sizeof(guess));
For more on this point, see this question and also this answer.
Two. Your array guess for reading the user's guess is too small. Instead of making it size 10, make it size 500 or something. That way it will "never" overflow. Don't worry that you're wasting memory by doing that — memory is cheap.
The reason for making the input buffer huge is this: If you make the buffer small, you have to worry about the case that the user might type a too-long line and that fgets might not be able to read all of it. If you make the buffer huge, on the other hand, you can declare that the problem "won't happen" and that you therefore don't have to worry about it. And the reason you'd like to not worry about it it is that worrying about it is hard, and leads to problems like the one you've had here.
To use fgets strictly correctly, while worrying about the possibility that the user's input overflows the buffer, means detecting that it happened. If fgets didn't read all the input, that means it's still sitting there on the input stream, waiting to confuse the rest of your program. In that case, yes, you have to read or "flush" or discard it. That's what your line
while((ch = getchar()) != '\n' && ch != EOF);
tries to do — but the point is that you need to do that only if fgets had the not-big-enough problem. If fgets didn't have the problem — if the buffer was big enough — you don't want to do the flush-the-input thing, because it'll gobble up the user's next line of intended input instead, as you've discovered.
Now, with this said, I have to caution you. In general, a strategy of "make your arrays huge, so you don't have to worry about the possibility that they're not big enough" is not a good strategy. In the general case, that strategy leads to insecure programs and horrible security problems due to buffer overruns.
In this case, though, the problem isn't too bad. fgets is going to do its best not to write more into the destination array than the destination array can hold. (fgets will do a perfect job of this — a perfect job of avoiding buffer overflow — if you pass the size correctly, that is, if you fix problem one.) If the buffer isn't big enough, the worst problem that will happen is that the too-long part of the input line will stay on the input stream and get read buy a later input function, thus confusing things.
So you do always want to think about the exceptional cases, and think about what your program is going to do under all circumstances, not just the "good" ones. And for "real" programs, you do have to strive to make the behavior correct for all cases. For a beginning program like this one, though, I think most people would agree that it's fine to just use a huge buffer, and be done with it.
If you want to go for the extra credit, and perfectly handle the case where the user typed more than the fgets input buffer will hold, you're going to first have to detect that case. The code would look something like:
if(fgets(guess, guess_size, stdin) == NULL)
{
printf("error");
exit(EXIT_FAILURE);
}
if(guess[strlen(guess)-1] != '\n')
{
/* buffer wasn't big enough */
int ch = 0;
while((ch = getchar()) != '\n' && ch != EOF); // Flush the input buffer
/* now print an error message or something, */
/* and ask the user to try again with shorter input */
}
But the point is that you do the while((ch = getchar()) != '\n' && ch != EOF) thing only in the case where fgets failed to read the whole line, not in the case where it succeeded.
If you're still with me, here are two somewhat-important footnotes.
I suggested changing your get_input function to take a second parameter int guess_size, but it turns out a better type to use for the sizes of things is size_t, so a better declaration would be size_t guess_size.
I suggested the test if(guess[strlen(guess)-1] != '\n') to detect that fgets wasn't able to read a full line, but that could fail (pretty badly) in the obscure case where fgets somehow returned an empty line. In that case strlen(guess) would be 0, and we'd end up accessing guess[-1] to see if it was the newline character, which is undefined and wrong. In practice it's probably impossible for fgets to return an empty string (at least, as long as you give it a buffer bigger than 1 to read into), but it's probably easier to write the code in a safer way than to convince yourself that it can't happen. There are a bunch of questions elsewhere on SO about practically and efficiently detecting the case that fgets didn't read a full line successfully, but just now I can't find any of them.

Storing strings in array in C

I have read a lot of questions on this, and using them I have altered my code and have created code which I thought would work.
I think it's my understanding of C, which is failing me here as I can't see where I'm going wrong.
I get no compilation errors, but when I run i receive 'FileReader.exe has stopped working' from the command prompt.
My code is :
void storeFile(){
int i = 0;
char allWords [45440][25];
FILE *fp = fopen("fileToOpen.txt", "r");
while (i <= 45440){
char buffer[25];
fgets(buffer, 25, fp);
printf("The word read into buffer is : %s",buffer);
strcpy(allWords[i], buffer);
printf("The word in allWords[%d] is : %s", i, allWords[i]);
//allWords[i][strlen(allWords[i])-1] = '\0';
i = i + 1;
}
fclose(fp);
}
There are 45440 lines in the file, and no words longer than 25 char's in length. I'm trying to read each word into a char array named buffer, then store that buffer in an array of char arrays named allWords.
I am trying to get this part working, before I refactor to return the array to the main method (which I feel won't be a fun experience).
You are trying to allocate more than a megabyte (45440*25) worth of data in automatic storage. On many architectures this results in stack overflow before your file-reading code even gets to run.
You can work around this problem by allocating allWords statically, like this
static char allWords [45440][25];
or dynamically, like this:
char (*allWords)[25] = malloc(45440 * sizeof(*allWords));
Note that using buffer in the call to fgets is not required, because allWords[i] can be used instead, without strcpy:
fgets(allWords[i], sizeof(*allWords)-1, fp);
Also note that an assumption about file size is unnecessary: you can continue calling fgets until it returns NULL; this indicates that the end of the file has been reached, so you can exit the loop using break.

code immediately stops responding (c, pointers, file I/O)

I'm writing a code for homework that uses functions and pointers to read a file and fix the capitalization errors in it.
The goal is to read a pre-written file and fix it, adding line numbers to the beginning of each line. (i.e., tiTle -> 1. Title)
I think I've got the basic logic down, but there must be a bug that I'm not seeing, because it stops responding immediately after I compile and run it.
Here's my main() function.
FILE *casefixer;
casefixer = fopen("casefixer.txt", "r+");
char* ch;
int* char_in_word;
int* line_num;
*char_in_word = 0;
*line_num = 1;
while((fscanf(casefixer, "%c", ch)) != EOF){
fscanf(casefixer, "%c", ch);
fprintf(casefixer, "%d. ", *line_num);
if(fix_caps(ch, char_in_word, line_num))
fprintf(casefixer, "\n");
fix_caps(ch, char_in_word, line_num);
fprintf(casefixer, "%c", *ch);
}
fclose(casefixer);
char* ch; // uninitialized
int* char_in_word; // -||-
int* line_num; // -||-
*char_in_word = 0; // dereferencing uninitialized pointer - undefined behavior
*line_num = 1; // -||-
You don't have to use pointers when you see them in function declaration. If you're sure the function won't store them or try to allocate new memory for them, take an address of a regular variable:
char ch;
fscanf(casefixer, "%c", &ch) // ch is on stack longer than fscanf, everything's OK
By using "%c" you can only read a single character instead of a line. I recommend you use fgets here.
The call of fscanf in the loop should be deleted since you've already called that in the while((fscanf(casefixer, "%c", ch)) != EOF).
Writing while reading is not easy, especially when you want to rewrite what you've read before. You need to reposition your stream position indicator. So I think the better way should be you store your new file into a buffer and then write the buffer into the file.
In this two lines:
if(fix_caps(ch, char_in_word, line_num))
fprintf(casefixer, "\n");
If I understand it right, you should use "continue" in this if statement.
In your code, the variable line_num is always 1. You should do the increment at the end of loop.

`read()` system call in C does not read bytes

I'm trying to read characters from a file and count the frequency of a particular word in a file using system calls, but the behavior of one of my read() calls is confusing me. This is the code that I've written:
int counter, seekError,readVal;
counter = 0;
char c[1];
char *string = "word";
readVal = read(fd,c,1);
while (readVal != 0){ // While not the end of the file
if(c[0] == string[0]) { // Match the first character
seekError = lseek(fd,-1,SEEK_CUR); // After we find a matching character, rewind to capture the entire word
char buffer[strlen(string)+1];
buffer[strlen(string)] = '\0';
readVal = read(fd,buffer,strlen(string)); // This read() does not put anything into the buffer
if(strcmp(lowerCase(buffer),string) == 0)
counter++;
lseek(fd,-(strlen(string)-1),SEEK_CUR); // go back to the next character
}
readVal = read(fd,c,1);
}
In all the read calls that I use, I am able to read characters with no problem from my file. However, the readVal = read(fd,buffer,strlen9string)); line never puts anything into buffer, no matter how I try to read the characters. Is there anything going on behind the scenes that would explain this kind of behavior? I've tried running this code on different machines as well, but I still get nothing in buffer at that line.
It shouldn't be necessary to cast -1 into the off_t type. It looks like your real bug is that you didn't include <unistd.h> so lseek wasn't properly declared when you used it. Either that or there's a serious bug in your system's implementation of lseek.
The problem here was that the -1 in the seekError = lseek(fd,-1,SEEK_CUR); line was being interpreted as 4294967295. After casting it into the off_t type, the system interpreted the offset as -1 instead of the large number.
So the corrected line is: seekError = lseek(fd,(off_t)-1,SEEK_CUR);

How to read empty string in C

I have a problem with reading empty string in C. I want to read string from the following -
ass
ball
(empty)
cat
but when I use gets() it does not treat (empty) as string[2]. It reads 'cat' as string[2]. So how can I solve this problem?
char str1[15002][12];
char str2[15002][12];
char s[25];
map<string,int> Map;
int main()
{
int ncase, i, j, n1, n2, count, Case;
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&ncase);
Case = 1;
while(ncase > 0)
{
Map.clear();
//this is the necessery part
scanf("%d %d\n",&n1,&n2);
count = 0;
printf("n1=%d n2=%d\n",n1,n2);
for(i = 0; i < n1; i++)
{
gets(str1[i]);
}
for(i = 0; i < n2; i++)
{
gets(str2[i]);
}
//end of reading input
for(i = 0; i < n1; i++)
{
for(j = 0; j < n2; j++)
{
strcpy(s,str1[i]);
strcat(s,str2[j]);
if(Map[s] == 0){
count += 1;
Map[s] = 1;
}
}
}
printf("Case %d: %d\n", Case, count);
Case++;
ncase--;
}
return 0;
}
and input can look like
I have given the code here. The input may be like
line1>1
line2>3 3
line3>(empty line)
line4>a
line5>b
line6>c
line7>(empty)
line8>b
And I expect
str1[0]=(empty).
str1[1]=a;
str1[2]=b;
and
str2[0]=c;
str2[1]=(empty);
str2[2]=b;
OK, at last I found the problem. It is the line
printf("n1=%d n2=%d\n",n1,n2);
which creates problem in taking input by gets(). Instead of taking newline with the integer n1, n2, then I take newline as a ("%c",&ch) and then everything is okay.
Thanks to everyone who answered me.
Chances are, the string contains \r\n\0 (or \n\r\0 - never remember which comes first). \r\n is newline on Windows and \0 is the terminating character of the string.
In general, if the first character of the string is \r or\n, you read an empty string. FWIW this should work on all platforms:
char* string;
// initialize string and read something into it
if (strlen(string) == 0 || string[0] == `\r` || string[0] == `\n`)
// string is empty
Update: you mention that you use gets, and read from a file. However, for the latter you need fgets, so there is some confusion here. Note that fgets includes the trailing newline character in the string returned, while gets does not.
Update3: The way you read from the file is indeed fishy. You reopen the standard input to read from the file - why??? The standard practice is to fopen the file, then read from it with fscanf and fgets.
Update2: stupid us (and clever #Salil :-). You say
it read 'cat' as string[3]
Since C arrays are indexed from 0, string[3] contains the 4th line read! The third line is stored in string[2] - I bet that will contain the empty string you are looking for.
Output of this code:
#include <cstdio>
int main ()
{
int i = 0;
char string [256];
while (gets(string)) {
++i;
}
printf("%d\n", i);
return 0;
}
For this input
a
b
d
Is
4
Which means, gets() reads all lines correctly, which in turn means your code must be screwed up. Post it here.
First and foremost, do not use gets!!!!! It is a buffer overflow vulnerability, since you cannot specify the size of the destination buffer, and so gets() can easily overrun your buffer. Instead, use fgets() or getchar().
Since you are using map<string,int>, it is clear that you are actually using C++ code. In that case, an even better approach is to use the C++ iostreams libraries for your input and output.
Now that I've done with my rant, the problem is this... gets -- which, again, you should never ever use -- according to the spec, will read up until a newline, and "any <newline> shall be discarded". The function fgets() will copy the newline into the destination buffer, giving you the desired behavior.
If there is no string, how do you expect to read it?
Please give us a piece of code :)
==Later edit ==
OK:
"gets() reads a line from stdin into the buffer pointed to by s until either a terminating newline or EOF, which it replaces with '\0'. "
So basically, if you have:
char x[3];
gets(x);
Then this function will fill in x[0] with '\0'
If you read the manpage you'll see that gets is not recommended. Use fgets instead

Resources