Function get_word is supposed to read word from stdin and save it. Saving next word after white char and return EOF on EOF but I am still getting in infinite loop. htab_lookup_add is some function to save word into table. There also seems to be a problem "Too long message" never prints but that's not the problem I am trying to solve now.
int get_word(char *s, int max, FILE *f){
s = malloc(sizeof(char) * max);
int c;
int i = 0;
while((c = getc(f))){
if(i > max || isspace(c)){
break;
}
s[i++] = c;
}
s[i] = '\0';
if(c == EOF){
return EOF;
}
return i;
}
while(get_word(word, (maxchar + 1), stdin) != EOF){
if(strlen(word) > maxchar){
printf("Too long!\n");
}
htab_lookup_add(table, word);
}
This loop:
while((c = getc(f))){
...
}
will terminate only when getc() returns zero, i.e., when it reads a null character '\0'. And when it returns EOF you'll store that value (converted to char) in s[i] and continue looping.
The test for EOF after the loop will never match.
You need to end the loop when it returns EOF. The usual idiom is:
while ((c = getc(f)) != EOF) {
...
}
Related
char *myfgets(char *s, int n, FILE *in) {
char ch;
if (n<=0) {
return s;
}
while (((ch = getc(in)) != '\n')) {
if(ch == EOF){
return NULL;
}
else if (ch == '\n') {
break;
} else {
*s=ch;
s++;
}
}
*s = '\n';
if (ferror(in) != 0) {
return NULL;
} else {
return s;
}
if (strlen(s) > 512) {
return NULL;
}
}
I want to take 1 line only from some specific file and put the line into the char pointer (*s). I made this function but when I run the program it didn't work really well. For the result, there are a lot of unknown characters that are displayed.
Is there anything wrong with my code?
From the man page of strlen():
The strlen() function calculates the length of the string pointed to by s, excluding the terminating null byte ('\0').
So, strlen counts the number of characters until it finds a null byte '\0', and not the newline character '\n'. Consider changing
*s = '\n'
to
*s = '\0'
Alternatively, you could write your own strlen that looks for '\n' instead of '\0'.
#include <stdio.h>
#include <string.h>
int mygetchar();
int main(){
mygetchar();
}
int mygetchar(){
int c, i = 0;
char line[1000];
while ((c = getchar()) != EOF && c != '\n'){
line[i] = c;
i++;
}
line[i] = '\0';
printf("%s\n", line);
printf("%lu\n", strlen(line));
return 0;
}
please see the picture of my code, my code can only come out with one string and one line of a file, but I want store each line of the file as a string and count their length and I can't use fgets, I can only use the getchar function, please help, thanks a lot.
Since your code basically handles characters until it reaches end of line or end of file, you can simply put another loop around it to do each line.
That would go something like:
int c = '\n'; // force entry into loop
while (c != EOF) {
int i = 0;
char line[1000];
while ((c = getchar()) != EOF && c != '\n') {
line[i] = c; // should really check for buffer overflow here.
i++;
}
line[i] = '\0'; // and here.
printf ("%s\n", line);
printf ("%lu\n", strlen (line));
}
Alternatively, you could just process all characters one by one, doing special handling for end of line (again, you should avoid buffer overflow, and you should probably move the common code into a function):
int c, i = 0;
char line[1000];
while ((c = getchar()) != EOF) {
// Newline is special, print and reset.
if (c == '\n') {
line[i] = '\0';
printf ("%s\n", line);
printf ("%lu\n", strlen (line));
i = 0;
} else {
line[i] = c;
i++;
}
}
// If data at end without newline.
if (i != 0) {
line[i] = '\0';
printf ("%s\n", line);
printf ("%lu\n", strlen (line));
}
I'm trying to write a program to read a file of an unknown size / line size but I'm having some issues detecting the new line character.
When I run the program, it never reaches the end of the line point within the while loop in readFile and will just run constantly. If I run print each character, it prints out some unknown char.
I've tried setting ch to be an int value and typecasting to char for \n comparison. It's not reaching the EOF condition either so I'm not sure what is going on.
code:
void readFile(FILE* file)
{
int endOfFile = 0;
while (endOfFile != 1)
{
endOfFile = readLine(file);
printf("%d\n", endOfFile);
}
}
int readLine(FILE* file)
{
static int maxSize = LINE_SIZE;
int currentIndex = 0;
int endOfFile = 0;
char* buffer = (char*) malloc(sizeof(char) * maxSize);
char ch;
do
{
ch = fgetc(file);
if ((ch != EOF) || (ch != '\n'))
{
buffer[currentIndex] = (char) ch;
currentIndex += 1;
}
if (currentIndex == maxSize)
{
printf("Reallocating string buffer");
maxSize *= 2;
buffer = (char*) realloc(buffer, maxSize);
}
} while ((ch != EOF) || (ch != '\n'));
if (ch == EOF)
{
endOfFile = 1;
}
parseLine(buffer);
free(buffer);
return endOfFile;
}
If someone could help me that would be greatly appreciated because I have been stuck on this issue for quite some time. Thanks in advance.
(ch != EOF) || (ch != '\n')
This is always true.
You want an && (AND) here, both in your if and while, otherwise it will never stop.
Just use this boilerplate standard construct
int ch; /* important, EOF is -1, not in the range 0-255 */
FILE *fp;
/* double brackets prevent warnings about assignment in if */
while ( (ch = fgetc(fp)) != EOF)
{
/* we now have a valid character */
/* usually */
if(ch == endofinputIlike)
break;
}
/* here you have either read all the input up to what you like
or skip because of EOF. usually you will set N or something,
or if N == 0 it was EOF, or we can test ch for EOF */
Generally assignment in if is a bad idea, but this particular snippet is so idiomatic that every experienced C programmer will instantly recognise it.
first of all i'm new to coding in C.
I tried to read a string of unknowns size from the user until a blank line is given and then save it to a file, and after that to read the file.
I've only managed to do it until a new line is given and I don't know how to look for a blank line.
#include <stdio.h>
#include <stdlib.h>
char *input(FILE* fp, size_t size) {
char *str;
int ch;
size_t len = 0;
str = realloc(NULL, sizeof(char)*size);
if (!str)return str;
while (EOF != (ch = fgetc(fp)) && ch != '\n') {
str[len++] = ch;
if (len == size) {
str = realloc(str, sizeof(char)*(size += 16));
if (!str)return str;
}
}
str[len++] = '\0';
return realloc(str, sizeof(char)*len);
}
int main(int argc, const char * argv[]) {
char *istr;
printf("input string : ");
istr = input(stdin, 10);
//write to file
FILE *fp;
fp = fopen("1.txt", "w+");
fprintf(fp, istr);
fclose(fp);
//read file
char c;
fp = fopen("1.txt", "r");
while ((c = fgetc(fp)) != EOF) {
printf("%c", c);
}
printf("\n");
fclose(fp);
free(istr);
return 0;
}
Thanks!
I would restructure your code a little. I would change your input() function to be a function (readline()?) that reads a single line. In main() I would loop reading line by line via readline().
If the line is empty (only has a newline -- use strcmp(istr, "\n")), then free the pointer, and exit the loop. Otherwise write the line to the file and free the pointer.
If your concept of an empty line includes " \n" (prefixed spaces), then write a function is_only_spaces() that returns a true value for a string that looks like that.
While you could handle the empty line in input(), there is value in abstracting the line reading from the input termination conditions.
Why not use a flag or a counter. For a counter you could simply increase the counter each character found. If a new line is found and the counter is 0 it must be a blank line. If a new line character is found and the counter is not 0, it must be the end of the line so reset the counter to 0 and continue.
Something like this:
int count = 0;
while ((ch = fgetc(fp)) != EOF)
{
if(ch == '\n')
{
if(count == 0)
{
break;
}
count = 0;
str[len++] = ch;
}
else
{
str[len++] = ch;
ch++;
}
}
Another way would be to simply check if the last character in the string was a new line.
while ((ch = fgetc(fp)) != EOF)
{
if(ch == '\n' && str[len - 1] == '\n')
{
break;
}
}
A blank line is a line which contains only a newline, right ? So you can simply keep the last 2 characters you read. If they are '\n', then you have detected a blank line : the first '\n' is the end of the previous line, the second one is the end of the current line (which is a blank line).
char *input(FILE* fp, size_t size) {
char *str;
int ch, prev_ch;
size_t len = 0;
str = realloc(NULL, sizeof(char)*size);
if (!str)return str;
while (EOF != (ch = fgetc(fp)) && (ch != '\n' && prev_ch != '\n')) {
str[len++] = ch;
if (len == size) {
str = realloc(str, sizeof(char)*(size += 16));
if (!str)return str;
}
prev_ch = ch;
}
str[len++] = '\0';
return realloc(str, sizeof(char)*len);
}
Note that parenthesis around ch != '\n' && prev_ch != '\n' are here to make the condition more understandable.
To improve this, you can keep your function that reads only a line and test if the line returned is empty (it contains only a '\n').
For a class I have to write a program to read in a text file in the format of:
T A E D Q Q
Z H P N I U
C K E W D I
V U X O F C
B P I R G K
N R T B R B
EXIT
THE
QUICK
BROWN
FOX
I'm trying to get the characters into an array of chars, each line being its own array.
I'm able to read from the file okay, and this is the code I use to parse the file:
char** getLinesInFile(char *filepath)
{
FILE *file;
const char mode = 'r';
file = fopen(filepath, &mode);
char **textInFile;
/* Reads the number of lines in the file. */
int numLines = 0;
char charRead = fgetc(file);
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
numLines++;
}
charRead = fgetc(file);
}
fseek(file, 0L, SEEK_SET);
textInFile = (char**) malloc(sizeof(char*) * numLines);
/* Sizes the array of text lines. */
int line = 0;
int numChars = 1;
charRead = fgetc(file);
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
textInFile[line] = (char*) malloc(sizeof(char) * numChars);
line++;
numChars = 0;
}
else if(charRead != ' ')
{
numChars++;
}
charRead = fgetc(file);
}
/* Fill the array with the characters */
fseek(file, 0L, SEEK_SET);
charRead = fgetc(file);
line = 0;
int charNumber = 0;
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
line++;
charNumber = 0;
}
else if(charRead != ' ')
{
textInFile[line][charNumber] = charRead;
charNumber++;
}
charRead = fgetc(file);
}
return textInFile;
}
This is a run of my program:
Welcome to Word search!
Enter the file you would like us to parse:testFile.txt
TAEDQQ!ZHPNIU!CKEWDI!VUXOFC!BPIRGK!NRTBRB!EXIT!THE!QUICK!BROWN!FOX
Segmentation fault
What's going on? A), why are the exclamation marks there, and B) why do I get a seg fault at the end? The last thing I do in the main is iterate through the array/pointers.
1) In the first part of your program, you are miscounting the number of lines in the file. The actual number of lines in the file is 11, but your program gets 10. You need to start counting from 1, as there will always be at least one line in the file. So change
int numLines = 0;
to
int numLines = 1;
2) In the second part of the program you are miscounting the number of characters on each line. You need to keep your counter initializations the same. At the start of the segment you initialize numChars to 1. In that case you need to reset your counter to 1 after each iteration, so change:
numChars = 0;
to
numChars = 1;
This should provide enough space for all the non-space characters and for the ending NULL terminator. Keep in mind that in C char* strings are always NULL terminated.
3) Your program also does not account for differences in line termination, but under my test environment that is not a problem -- fgetc returns only one character for the line terminator, even though the file is saved with \r\n terminators.
4) In the second part of your program, you are also not allocating memory for the very last line. This causes your segfault in the third part of your program when you try to access the unallocated space.
Note how your code only saves lines if they end in \r or \n. Guess what, EOF which technically is the line ending for the last line does not qualify. So your second loop does not save the last line into the array.
To fix this, add this after the second part:
textInFile[line] = (char*) malloc(sizeof(char) * numChars);
4) In your program output you are seeing those weird exclamation points because you are not NULL terminating your strings. So you need to add the line marked as NULL termination below:
if(charRead == '\n' || charRead == '\r')
{
textInFile[line][charNumber] = 0; // NULL termination
line++;
charNumber = 0;
}
5) Because you are checking for EOF, you have the same problem in your third loop, so you must add this before the return
textInFile[line][charNumber] = 0; // NULL termination
6) I am also getting some headaches because of the whole program structure. You read the same file character by character 3 times! This is extremely slow and inefficient.
Fixed code follows below:
char** getLinesInFile(char *filepath)
{
FILE *file;
const char mode = 'r';
file = fopen(filepath, &mode);
char **textInFile;
/* Reads the number of lines in the file. */
int numLines = 1;
char charRead = fgetc(file);
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
numLines++;
}
charRead = fgetc(file);
}
fseek(file, 0L, SEEK_SET);
textInFile = (char**) malloc(sizeof(char*) * numLines);
/* Sizes the array of text lines. */
int line = 0;
int numChars = 1;
charRead = fgetc(file);
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
textInFile[line] = (char*) malloc(sizeof(char) * numChars);
line++;
numChars = 1;
}
else if(charRead != ' ')
{
numChars++;
}
charRead = fgetc(file);
}
textInFile[line] = (char*) malloc(sizeof(char) * numChars);
/* Fill the array with the characters */
fseek(file, 0L, SEEK_SET);
charRead = fgetc(file);
line = 0;
int charNumber = 0;
while (charRead != EOF)
{
if(charRead == '\n' || charRead == '\r')
{
textInFile[line][charNumber] = 0; // NULL termination
line++;
charNumber = 0;
}
else if(charRead != ' ')
{
textInFile[line][charNumber] = charRead;
charNumber++;
}
charRead = fgetc(file);
}
textInFile[line][charNumber] = 0; // NULL termination
return textInFile;
}
You aren't null terminating your arrays. This probably explains both problems. Be sure to allocate an extra character for the null terminator.
Do This:
if(charRead == '\n')
{
textInFile[line] = (char*) malloc(sizeof(char) * (numChars+1));
line++;
numChars = 0;
}
Then:
if(charRead == '\n')
{
textInFile[line][charNumber]='\0';
line++;
charNumber = 0;
}
Also you are reading the file 3 times! This thread has some good explanation on how to read a file efficiently.