Can't stop reading Unicode file with !feof() - c

I don't know why while loop can't stop. It can't compare c with Delim neither stop by reaching eof.
wchar_t* Getline(const wchar_t* Filename, const wchar_t Delim){
FILE* f = _wfopen(Filename, L"r, ccs=UTF-8");
wchar_t* info = NULL;
wchar_t* temp = NULL;
int count = 1;
int i = 0;
wchar_t c;
c = fgetwc(f);
while (c != Delim || !feof(f))
{
count++;
temp = (wchar_t*)realloc(info, count * sizeof(wchar_t));
if (temp)
{
info = temp;
info[i] = c;
i++;
}
else
{
free(info);
wprintf(L"Failed to read\n");
}
c = fgetwc(f);
}
info[i] = '\0';
fclose(f);
return info;
}
After reading all character in file. It seem not to stop. Even c are the same with Delim. And !feof(f) hasn't worked too. I have try c != WEOF but fail too
I thought that the problem is in the file that I read but not. I have change another file but the same problem.
Thanks for helping me!

You wish to loop whilst you have not got a Delim character and it is not the end of the file, so replace the || with &&
while (!feof(f) && c != Delim)
Edit: the order has also been changed in response to comments

Related

Reading multiple lines from input in C

I am trying to read multiple lines from console input, but I can't really figure out the way to do it. I made a code that reads only the first line and tried to loop that, but I couldn't figure out the way that works. Any help is welcomed. Thanks in advance. Here is the code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char* readLine() {
char* line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax;
int c;
if (line == NULL)
return NULL;
for (;;) {
c = fgetc(stdin);
if (c == EOF || c == '\n')
break;
if (--len == 0) {
len = lenmax;
char* linen = realloc(linep, lenmax *= 2);
size_t diff = line - linep;
if (linen == NULL) {
free(linep);
return NULL;
}
line = linen + diff;
linep = linen;
}
*line++ = c;
}
*line = '\0';
return linep;
}
int main() {
for (int i = 0; i < 2; i++) {
printf("%s", readLine());
}
return 0;
}
As you can see, I only managed to loop the function calling twice, which just means I will read only one line twice.
EDIT: I found a way to read code line by line, by doing all the work to the line immediately after its input (saving all I need before the next line is inputted), and tried to stop the while loop while its != '\n', but the loop won't stop, instead it just keeps printing the '\n' character (I keep getting blank lines). Any help on how to fix this?
// Same stuff here
int main() {
char* temp = readLine();
while (*temp != '\n') {
char* temp = readLine();
printf("%s\n", temp);
}
return 0;
}

Replacing strings in C

Okay, guys, I have to write a program that forms a new string based on the given template and the given strings. The template is set as a string where it is necessary to replace all occurrences of the character '%' with a concrete string. If the template contains more characters '%' than the entered strings, characters '%' replaces strings cyclically. If no string is entered, print "ERROR". The number of strings is not known in advance. The end of the entry is indicated by a blank line ("\n").
Also, there are some conditions I need to fulfill, which are:
1) Implement char * readLine () function; which reads one row from the standard input and returns the pointer to that loaded row.
2) Implement char ** readLines (int * n) function; which reads strings that change all occurrences of the character '%' in the template. The function returns an array of pointers to the strings entered as a return value. Also, the function returns the number of values entered via argument n.
3) Implement char * format function (char * format, char ** values, int n); which formats the string format by changing each occurrence of the '%' character to a corresponding string from a string of values of length n.
4) Write a master program that, using previously implemented functions, reads the template and strings from the standard input, forms a new string as described, and prints the result to standard output.
I barely understand what I'm supposed to do so I came here to ask for help. What I did for now is the first task, but on the output I get 1 more blank line than I'm supposed to and I can't find any way to fix it. Any kind of help is welcomed since I'm really stuck here, even explaining what I'm supposed to do in some tasks, or making current code simpler is awesome. Thanks in advance. Here is my code.
EDIT: Added examples.
Input:
% be or not % be.
To
Output:
To be or not To be.
Input:
% and % make purple.
Blue
red
Output:
Blue and red make purple.
#include<stdio.h>
#include<stdlib.h>
char* readLine() {
char* line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax;
int c;
if (line == NULL)
return NULL;
for (;;) {
c = fgetc(stdin);
if (c == EOF)
break;
if (--len == 0) {
len = lenmax;
char* linen = realloc(linep, lenmax *= 2);
if (linen == NULL) {
free(linep);
return NULL;
}
line = linen + (line - linep);
linep = linen;
}
if ((*line++ = c) == '\n')
break;
}
*line = '\0';
return linep;
}
int main() {
printf("%s", readLine());
return 0;
}
EDIT: For the 2nd task, I tried to do something similar like in the first, but I couldn't really figure out how to make it so that it works. Here is what I did:
char** readLines(int* n) {
char* line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax;
int c, flag = 0;
if (line == NULL && flag > 1) {
char* linen = realloc(linep, lenmax *= 2);
}
else if (line == NULL && flag == 0)
return NULL;
for (;;) {
c = fgetc(stdin);
if (c == EOF || c == '\n')
break;
if (--len == 0) {
len = lenmax;
char* linen = realloc(linep, lenmax *= 2);
size_t diff = line - linep;
if (linen == NULL) {
free(linep);
return NULL;
}
line = linen + diff;
linep = linen;
flag++;
}
*line++ = c;
}
*line = '\0';
char* temp = linep;
return linep;
}
At least this problem
line = linen + (line - linep); is UB, as code cannot use linep after it has been free'd in realloc().
Instead calculate and save the line - linep difference before realloc()
size_t diff = line - linep; // add
char* linen = realloc(linep, lenmax *= 2);
if (linen == NULL) {
...;
}
// line = linen + (line - linep);
line = linen + diff;
OP apparently does not want to retain the '\n'. Change
// if ((*line++ = c) == '\n') break;
if (c == '\n') break;
*line++ = c;
I'd also recommend a right size realloc() step in the end.
If you want to read a line until EOF or '\n', but without the newline in your string, you need to do this:
for (;;) {
c = fgetc(stdin);
if (c == EOF)
break;
// realloc logic comes here
if (c == '\n')
break;
*line++ = c;
}

I want to read a certain part of a line in C

I want to read a specific part of a line. I don't want to add anything after "// " as shown in the example. I've defined a flag for it. But I'm having a hard time getting to the bottom line. How can I solve this ?
void read_file(char *filename) {
int flag = 0;
char line[MAX_LINE_LENGTH];
FILE *f = fopen(filename, "r");
while(fscanf(f, "%s", line) != EOF) {
if(!strcmp(line, "//")) {
flag = 1;
}
if(flag == 0) {
printf("%s", line);
}
}
}
Your fscanf is wrong. It won't return EOF. You want to compare against != 1 instead.
But, if you want to strip the comment, and just print the [preceding] data, you'll want strstr instead of strcmp
Also, I'd use fgets instead of fscanf ...
Here's your code refactored:
#include <stdio.h>
#include <string.h>
#define MAX_LINE_LENGTH 1000
void
read_file(char *filename)
{
int flag = 0;
char *cp;
char line[MAX_LINE_LENGTH];
FILE *f = fopen(filename, "r");
while (1) {
cp = fgets(line,sizeof(line),f);
if (cp == NULL)
break;
cp = strstr(line,"//");
if (cp != NULL) {
*cp++ = '\n';
*cp = 0;
}
printf("%s", line);
}
}
You may want to clean this up a bit more to do better handling of the newline [which fgets retains].
UPDATE:
Yes, my code is fixed. Thank you so much. But I don't understand here : *c = 0
A string in C is a char array that just "happens" to have a zero byte as the string terminator.
fgets will guarantee that the buffer has a trailing 0
Likewise, printf expects line to be 0 terminated.
We're trying to clip out the // and everything else on the line that follows it.
It's not enough to just add back a newline there. We have to add [back] the 0 at the now shortened string as the new place for the string terminator.
If the original line was:
foo // bar<newline><0x00>
We want:
foo <newline><0x00>
If you want to see why, just comment out the *cp = 0;. You'll get "interesting" results ...
UPDATE #2:
In order to not change your code so much, I left the newline in the string.
But, normally, I always strip the newline out before doing any processing. I find that to be a bit cleaner [even if a bit slower].
Here's a version that does that and is closer to what I would have written from scratch:
#include <stdio.h>
#include <string.h>
#define MAX_LINE_LENGTH 1000
void
read_file(char *filename)
{
int flag = 0;
char *cp;
char line[MAX_LINE_LENGTH];
FILE *f = fopen(filename, "r");
while (1) {
cp = fgets(line,sizeof(line),f);
if (cp == NULL)
break;
// strip newline
cp = strchr(line,'\n');
if (cp != NULL)
*cp = 0;
// find [and strip] the comment
cp = strstr(line,"//");
if (cp != NULL)
*cp = 0;
printf("%s\n", line);
}
}
Note that because the newline has been pre-stripped [if it exists on the line], the printf has to be modified to add one when printing.
UPDATE #3:
Using strchr and strstr are the easy thing to do. But, this requires that line be scanned twice, which is a bit wasteful.
The str* functions in libc are a convenience, but we can write a custom function that does a single pass on the line and strips either the comment or the newline whichever comes first.
This may help explain what a "string" in C really is, since we're doing "all the magic" so to speak:
#include <stdio.h>
#include <string.h>
#define MAX_LINE_LENGTH 1000
void
fixline(char *line)
{
int chr;
for (chr = *line++; chr != 0; chr = *line++) {
// strip newline
if (chr == '\n') {
line[-1] = 0;
break;
}
// wait for first "/"
if (chr != '/')
continue;
// peek at next char (is it '/' -- if so, we have "//")
chr = *line;
if (chr == '/') {
line[-1] = 0;
break;
}
}
}
void
read_file(char *filename)
{
int flag = 0;
char *cp;
char line[MAX_LINE_LENGTH];
FILE *f = fopen(filename, "r");
while (1) {
cp = fgets(line,sizeof(line),f);
if (cp == NULL)
break;
// strip newline and/or comment
fixline(line);
printf("%s\n", line);
}
}
UPDATE #4:
Thank you I got it. But when I try it this way, why can't I get the right result? if(!strcmp("data", line)) { printf("helloo"); } break; When you add this part to the end of the code, it doesn't work correctly.
If you've added this after the newline strip, it should work, because the data line has nothing else on it and it starts in the first position of the buffer.
But, indented this is:
if (!strcmp("data", line)) {
printf("helloo");
}
break;
You probably want:
if (!strcmp("data", line)) {
printf("helloo");
break;
}
Both strchr and strstr scan the entire string looking for a matching character [strchr]. Or, the start of matching substring [strstr].
strcmp does not scan the string in that sense. It just loops through both strings, char-by-char and stops on EOS. It just checks for equal strings, both starting at the first char of each array.
Real strcmp will use special instructions to make it very fast [as will other libc functions], but here is what strcmp actually does:
int
strcmp(const char *s1,const char *s2)
{
int c1;
int c2;
int cmp = 0;
while (1) {
c1 = *s1++;
c2 = *s2++;
if (c1 < c2) {
cmp = -1;
break;
}
if (c1 > c2) {
cmp = +1;
break;
}
// end of string -- both strings equal
if (c1 == 0)
break;
}
return cmp;
}
Format %s reads words (i.e. everything until the next space, tab, newline, ...) but not lines; That's probably why you have a hard time.
For reading in complete lines (i.e. everything up to a new line), use function fgets;
For cutting the line off at a "//", use strstr as follows:
char *beginOfComment = strstr(line,"//");
if (beginOfComment) {
*beginOfComment = 0x0;
}
#Craig Estey
while (1)
{
cp = fgets(line, sizeof(line), f);
if (cp == NULL)
break;
if(!strcmp("actions", cp)) {
break;
}
cp = strstr(line, "//");
if (cp != NULL)
{
*cp++ = '\n';
*cp = 0;
}
printf("%s", line);
}
Why is the strcmp function not working in this way?

Read all data from stdin C

I've wrote this small function to read all the data from stdin.
I need to know if this function is POSIX compatible (by this, I mean it will work under Unix and Unix-like systems) at least it works on Windows...
char* getLine()
{
int i = 0, c;
char* ptrBuff = NULL;
while ((c = getchar()) != '\n' && c != EOF)
{
if ((ptrBuff = (char*)realloc(ptrBuff, sizeof (char)+i)) != NULL)
ptrBuff[i++] = c;
else
{
free(ptrBuff);
return NULL;
}
}
if (ptrBuff != NULL)
ptrBuff[i] = '\0';
return ptrBuff;
}
The function reads all the data from stdin until get '\n' or EOF and returns a pointer to the new location with all the chars. I don't know if this is the most optimal or safer way to do that, and neither know if this works under Unix and Unix-like systems... so, I need a little bit of help here. How can I improve that function? or is there a better way to get all the data from stdin without leaving garbage on the buffer? I know that fgets() is an option but, it may leave garbage if the user input is bigger than expected... plus, I want to get all the chars that the user has written.
EDIT:
New version of getLine():
char* readLine()
{
int i = 0, c;
size_t p4kB = 4096;
void *nPtr = NULL;
char *ptrBuff = (char*)malloc(p4kB);
while ((c = getchar()) != '\n' && c != EOF)
{
if (i == p4kB)
{
p4kB += 4096;
if ((nPtr = realloc(ptrBuff, p4kB)) != NULL)
ptrBuff = (char*)nPtr;
else
{
free(ptrBuff);
return NULL;
}
}
ptrBuff[i++] = c;
}
if (ptrBuff != NULL)
{
ptrBuff[i] = '\0';
ptrBuff = realloc(ptrBuff, strlen(ptrBuff) + 1);
}
return ptrBuff;
}
LAST EDIT:
This is the final version of the char* readLine() function. Now I can't see more bugs neither best ways to improve it, if somebody knows a better way, just tell me, please.
char* readLine()
{
int c;
size_t p4kB = 4096, i = 0;
void *newPtr = NULL;
char *ptrString = malloc(p4kB * sizeof (char));
while (ptrString != NULL && (c = getchar()) != '\n' && c != EOF)
{
if (i == p4kB * sizeof (char))
{
p4kB += 4096;
if ((newPtr = realloc(ptrString, p4kB * sizeof (char))) != NULL)
ptrString = (char*) newPtr;
else
{
free(ptrString);
return NULL;
}
}
ptrString[i++] = c;
}
if (ptrString != NULL)
{
ptrString[i] = '\0';
ptrString = realloc(ptrString, strlen(ptrString) + 1);
}
else return NULL;
return ptrString;
}
POSIX-compatible: yes!
You're calling only getchar(), malloc(), realloc() and free(), all of which are
standard C functions and therefore also available under POSIX. As far as I can tell, you've done all the necessary return code checks too. Given that, the code will be good in any environment that supports malloc() and stdin.
Only thing I would change is the last call to strlen, which is not necessary since the length is already stored in i.

Load File Into Char* Array

Feel silly asking this question, since this should be easy, but I can't figure out whats wrong.
void loadIniIntoMemory() {
FILE *fp ;
fp = fopen (iniFile, "r");
int ch;
int final_line_num = 0;
int char_index;
char* current_line = (char*) malloc(sizeof(char) * MAX_INI_LINE_LENGTH);
while((ch = fgetc(fp)) != EOF) {
if(ch == 10) {
// new line
*(current_line + char_index) = '\0';
char_index = 0;
iniFileData[final_line_num] = current_line;
final_line_num++;
} else {
// regular char
*(current_line + char_index) = ch; // CAN'T DO THIS, CRASH
char_index++;
if(ch == 13) {
// carriage return
continue;
}
}
}
}
Been a little while since I did C, it crashes at this line : *(current_line + char_index) = ch;
Thanks for any help.
--EDIT--
Also, no one noticed, that this code doesn't save the last line. Here is the full, correct, working code which saves a file into an array of pointers.
void loadIniIntoMemory() {
FILE *fp ;
fp = fopen (iniFile, "r");
int ch;
final_line_num = 0;
int char_index = 0;
char* current_line = (char*) malloc(sizeof(char) * MAX_INI_LINE_LENGTH);
while((ch = fgetc(fp)) != EOF) {
if(ch == '\n') {
// new line
*(current_line + char_index) = '\0';
char_index = 0;
iniFileData[final_line_num] = current_line;
final_line_num++;
current_line = (char*) malloc(sizeof(char) * MAX_INI_LINE_LENGTH);
} else if(ch != '\r') {
// regular char
*(current_line + char_index) = ch;
char_index++;
}
}
iniFileData[final_line_num] = current_line;
fclose(fp);
}
For starters, you don't initialize char_index, meaning it will likely have garbage in it. If you don't initialize it, your program will add some unknown number to the current_line pointer.
int char_index = 0; /* initialize to 0 */
Secondly, a bit more "natural" syntax would be:
current_line[char_index] = ...
Thirdly, you can test the characters without using their integer equivalents:
if (ch == '\n') {
/* this is the same as "ch == 10" */
Fourth, you should close the open file prior to leaving the routine:
fclose(fp);
Finally, I'm not sure what the ch == 13 ('\r') and continue is meant to handle, since the continue is effectively a no-op, but you probably don't want to copy it into the data:
if (ch != '\r') {
current_line[char_index] = ch;
char_index++;
/* or on one line: current_line[char_index++] = ch; */
}
As an aside, a powerful feature of C (and many other languages) is the switch statement:
/* substitutes your if...elseif...else */
switch (ch) {
case '\n':
current_line[char_index] = '\0';
char_index = 0;
iniFileData[final_line_num++] = current_line;
break; /* <-- very important, C allows switch cases to fall thru */
case '\r':
/* do nothing */
break;
default:
/* any character that is not a newline or linefeed */
current_line[char_index++] = ch;
break;
}
You didn't initialize char_index. I suppose you want to initialize it to 0. In C, uninitialized variable will contain garbage. Most likely your char_index equals some very large number.
Besides what others have already pointed out, you will also have to move the line buffer allocation call into the loop and immediately after the final_line_num++; statement. Otherwise, each new line you read will be overwriting the previous line.
And some operating systems, like most POSIX compliant ones, in particular Linux, gives you the ability to map a file segment (possibly the entire file) into virtual memory. On Linux, you could consider using the mmap system call

Resources