How not to go to the next line of file in c - c

I am pretty new to C Programming and I'm having problems with my code. My program opens a .txt file and stores the data inside it in a string. After that, the data stored in a string is copied into another .txt file.
FILE * fp = fopen("New.txt", "a");
FILE * fp2 = fopen("File.txt", "r");
while(fgets(str, 100, fp2) != NULL) {
fputs(str, fp);
}
fclose(fp);
fclose(fp2);
Now my problem here is, I want to store the strings in a single line, but my program always goes to the next line. For example, I want the data to be:
One Two Three
What my code does:
One
Two
Three
Can you help me? Thanks in advance.

fgets reads a line, but retains the new-line character at the end. When you write the line, that new line is printed as well. You can remove the new-line character explicitly, for example:
int len = strlen(str);
if (len && str[len - 1] == '\n') str[len - 1] = '\0';
Alternatively, you could choose another approach: Read the file character-wise with getc and print out all characters except new lines with putc. (That approach works only if you don't want to do other things that require you to know the contents of each line.)

Related

How to read the next line in a text file in C

I'm trying to read the next new line in a text file and place it into an array, I was able to place the first line to an array. But I want to place each line in the text file into in separate arrays, is there a way to jump to the next line in the text file?
Code:
while(((ch = getc(file1))!= '\n') && (i < 30))
{
day1_array[i] = ch;
printf("%c",ch);
}
Thanks in advance.
Do something like this:
while (fgets(buf, MAX_LEN - 1, fp))
{
printf("%s", buf);
}
where buf is some char array, MAX_LEN is the maximum expected line length and fp is the file pointer. The function fgets reads until either (n-1) characters are read, the newline character is read, or the end of file is reached. Must not be in this order, basically whichever come first

read file line by line including multiple newline characters

I am trying to read a file of unknown size line by line including single or multiple newline characters.
for example if my sample.txt file looks like this
abc cd er dj
text
more text
zxc cnvx
I want my strings to look something like this
string1 = "abc cd er dj\n";
string2 = "text\n\n";
string3 = "more text\n\n\n";
string4 = "zxc convex";
I can't seem to come up with solution that works properly. I have tried following code to get the length of each line including newline characters but it gives me incorrect length
while((temp = fgetc(input)) != EOF) {
if (temp != '\n') {
length++;
}
else {
if (temp == '\n') {
while ((temp = fgetc(input)) == '\n') {
length++;
}
}
length = 0;
}
}
I was thinking, if I can get length of each line including newline character(s) and then I can malloc string of that length and then read that size of string using fread but I am not sure if that would work because I will have to move the file pointer to get the next string.
I also don't want to use buffer because I don't know the length of each line. Any sort of help will be appreciated.
If the lines are just short and there aren't many of them, you could use realloc to reallocate memory as needed. Or you can use smaller (or larger) chunks and reallocate. It's a little more wasteful but hopefully it should average out in the end.
If you want to use just one allocation, then find the start of the next non-empty line and save the file position (use ftell). Then get the difference between the current position and the previous start position and you know how much memory to allocate. For the reading yes you have to seek back and forth but if it's not to big all data will be in the buffer to it's just modifying some pointers. After reading then seek to the saved position and make it the next start position.
Then you could of course the possibility to memory-map the file. This will put the file contents into your memory map like it was all allocated. For a 64-bit system the address space is big enough so you should be able to map multi-gigabyte files. Then you don't need to seek or allocate memory, all you do is manipulate pointers instead of seeking. Reading is just a simply memory copying (but then since the file is "in" memory already you don't really need it, just save the pointers instead).
For a very simple example on fseek and ftell, that is somewhat related to your problem, I put together this little program for you. It doesn't really do anything special but it shows how to use the functions in a way that could be used for a prototype of the second method I discussed above.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *file = fopen("some_text_file.txt", "r");
// The position after a successful open call is always zero
long start_of_line = 0;
int ch;
// Read characters until we reach the end of the file or there is an error
while ((ch = fgetc(file)) != EOF)
{
// Hit the *first* newline (which differs from your problem)
if (ch == '\n')
{
// Found the first newline, get the current position
// Note that the current position is the position *after* the newly read newline
long current_position = ftell(file);
// Allocate enough memory for the whole line, including newline
size_t bytes_in_line = current_position - start_of_line;
char *current_line = malloc(bytes_in_line + 1); // +1 for the string terminator
// Now seek back to the start of the line
fseek(file, start_of_line, SEEK_SET); // SEEK_SET means the offset is from the beginning of the file
// And read the line into the buffer we just allocated
fread(current_line, 1, bytes_in_line, file);
// Terminate the string
current_line[bytes_in_line] = '\0';
// At this point, if everything went well, the file position is
// back at current_position, because the fread call advanced the position
// This position is the start of the next line, so we use it
start_of_line = current_position;
// Then do something with the line...
printf("Read a line: %s", current_line);
// Finally free the memory we allocated
free(current_line);
}
// Continue loop reading character, to read the next line
}
// Did we hit end of the file, or an error?
if (feof(file))
{
// End of the file it is
// Now here's the tricky bit. Because files doesn't have to terminated
// with a newline, at this point we could actually have some data we
// haven't read. That means we have to do the whole thing above with
// the allocation, seeking and reading *again*
// This is a good reason to extract that code into its own function so
// you don't have to repeat it
// I will not repeat the code my self. Creating a function containing it
// and calling it is left as an exercise
}
fclose(file);
return 0;
}
Please note that for brevity's sake the program doesn't contain any error handling. It should also be noted that I haven't actually tried the program, not even tried to compile it. It's all written ad hoc for this answer.
Unless you are trying to write your own implementation, you can use the standard POSIX getline() function:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char *line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("/etc/motd", "r");
if (fp == NULL)
exit(1);
while ((read = getline(&line, &len, fp)) != -1) {
printf("Retrieved line of length %zu :\n", read);
printf("%s", line);
}
if (ferror(fp)) {
/* handle error */
}
free(line);
fclose(fp);
return 0;
}
You get the wrong length. The reason is that before you enter the loop:
while ((temp = fgetc(input)) == '\n')
you forgot to increment length as it has just read a \n character. So those lines must become:
else {
length++; // add the \n just read
if (temp == '\n') { // this is a redundant check
while ((temp = fgetc(input)) == '\n') {
length++;
}
ungetc(temp, input);
}
EDIT
After having read the first non \n, you now have read the first character of the next line, so you must unget it:
ungetc(temp, input);

File I/O issue - conflicting while loops

while (fgets(line, sizeof line, f)) {
int len = strlen(line);
if (length!=len-1){
fputs("max errorz\n", stderr);
exit(1);
}
break;
}
while ((c = getc(f)) != EOF) {
putchar(c);
}
I have a problem displaying all the contents in a text file. At the moment, the first while loop runs successfully, it checks the length of a file (characters), and if it matches the argument. I have finished this one, but for my 2nd loop after checking if the input matches the length of file , now i want to fully display the text file. BUT, it only displays 2/3 lines of the file. the first line looks like it was "taken" by the first loop.
Anyone know why this is?
I have tried putting the 2nd loop first, and it works (displays the full contents of the file).
When the first loop reads from the file, it advances the read offset. After, all you'd expect this to work, right?
fgets(line1, sizeof line1, f);
fgets(line2, sizeof line2, f);
/* line1 and line2 now hold the first two lines */
So calling getc after fgets behaves the same way - it reads from where you left off.
Just move back to the beginning again between loops:
fseek(stream, 0L, SEEK_SET);
or as pzaenger suggests, the equivalent
rewind(f);
When you call fgets on FILE* f, f's position in the file moves forward so subsequent calls will not read the same data. When you go to use getc f points to where the first loop left it, in the middle of the file. You want to put f back to the beginning of the file. Try rewind(f) as #pzaenger suggests.
After fetching some data from the file, file pointer moves some position forward from the starting position. if you want to set back the file pointer to starting position of the file you need to use rewind().
while (fgets(line, sizeof line, f)) {
int len = strlen(line);
if (length!=len-1){
fputs("max errorz\n", stderr);
exit(1);
}
break;
}
rewind(f); // fix
while ((c = getc(f)) != EOF) {
putchar(c);
}
1 - You are not necessary reading the whole lenght of your file. Read the documentation:
http://www.cplusplus.com/reference/cstdio/fgets/
2 - Why putting a break into a while command without any if around? This means that your break is always hit and so it means that you don't need the while. See the same link as before.
3 - You print only part of the file because you've already read part of it using the while, you have to rewind your pointer as suggested by others. Again see
http://www.cplusplus.com/reference/cstdio/rewind/?kw=rewind

Reading a specific line from a file in C

Okay, so after reading both: How to read a specific line in a text file in C (integers) and What is the easiest way to count the newlines in an ASCII file? I figured that I could use the points mentioned in both to both efficiently and quickly read a single line from a file.
Here's the code I have:
char buf[BUFSIZ];
intmax_t lines = 2; // when set to zero, reads two extra lines.
FILE *fp = fopen(filename, "r");
while ((fscanf(fp, "%*[^\n]"), fscanf(fp, "%*c")) != EOF)
{
/* globals.lines_to_feed__queue is the line that we _do_ want to print,
that is we want to ignore all lines up to that point:
feeding them into "nothingness" */
if (lines == globals.lines_to_feed__queue)
{
fgets(buf, sizeof buf, fp);
}
++lines;
}
fprintf(stdout, "%s", buf);
fclose(fp);
Now the above code works wonderfully, and I'm extrememly pleased with myself for figuring out that you can fscanf a file up to a certain point, and then use fgets to read whatever data is at said point into a buffer, instead of having to fgets every single line and then fprintf the buf, when all I care about is the line that I'm printing: I don't want to be storing strings that I could care less about in a buffer that I'm only going to use once for a single line.
However, the only issue I've run into, as noted by the // when set to zero, reads two extra lines comment: when lines is initialized with a value of 0, and the line I want is like 200, the line I'll get will actually be line 202. Could someone please explain what I'm doing wrong here/why this is happening and whether my quick fix lines = 2; is fine or if it is insufficient (as in, is something really wrong going on here, and it just happens to work?)
There are two reasons why you have to set the lines to 2, and both can be derived from the special case where you want the first line.
On one hand, in the while loop the first thing you do is use fscanf to consume a line, then you check if the lines counter matches the line you want. The thing is that if the line you want is the one you just consumed you are out of luck. On the other hand you are basically moving through lines by finding the next \n and incrementing lines after you check if the current line is the one you're after.
These two factors combined cause the offset in the lines count, so the following is a version of the same function taking them into account. Additionally it also contains a break; statement once you get to the line you are looking for, so that the while loop stops looking further into the file.
void read_and_print_line(char * filename, int line) {
char buf[BUFFERSIZE];
int lines = 0;
FILE *fp = fopen(filename, "r");
do
{
if (++lines == line) {
fgets(buf, sizeof buf, fp);
break;
}
}while((fscanf(fp, "%*[^\n]"), fscanf(fp, "%*c")) != EOF);
if(lines == line)
printf("%s", buf);
fclose(fp);
}
Just as another way of looking at the problem… Assuming that your global specifies 1 when the first line is to be printed, 2 for the second, etc, then:
char buf[BUFSIZ];
FILE *fp = fopen(filename, "r");
if (fp == 0)
return; // Error exit — report error.
for (int lineno = 1; lineno < globals.lines_to_feed_queue; lineno++)
{
fscanf(fp, "%*[^\n]");
if (fscanf(fp, "%*c") == EOF)
break;
}
if (fgets(buf, sizeof(buf), fp) != 0)
fprintf(stdout, "%s", buf);
else
…requested line not present in file…
fclose(fp);
You could replace the break with fclose(fp); and return; if that's appropriate (but do make sure you close the file before exiting; otherwise, you leak resources).
If your line numbers are counted from 0, then change the lower limit of the for loop to 0.
First, about what is wrong here: this code is unable to read the very first line in the file (what happens if globals.lines_to_feed__queue is 0?). It would also miscount lines shall the file contain successive newlines.
Second, you must realize that there is no magic. Since you don't know at which offset the string in question lives, you have to patiently read file character by character, counting end-of-strings along the way. It doesn't matter if you delegate the reading/counting to fgets/fscanf, or fgetc each character for manual inspection - either way an uninteresting piece of file will make its way from the disk into the OS buffers, and then into the userspace for interpretation.
Your gut feeling is absolutely correct: the code is broken.

string replace in file using C

I haven't yet implemented this, I'm still in the thinking stage, but I have to go through a file and replace a certain string with another string. For example,
<img src="/images/logo.gif" ...
should become
<img src="/proxy/www.example.com/images/logo.gif" ...
Any advice on how I can approach this? Perhaps there exist some "string replace" C functions that would do this for me that I don't know about...?
Right now, if I had to write this function myself, I would give it as parameters the file, string to replace, replacement string. Then I would manually go through the file and look for an occurrence of the string and recreate it. This, however, seems very inefficient. Are there better ways to do this?
Thanks,
Hristo
No, there is no function in C that replaces a string throughout a file. You must implement it yourself.
That said, what you're showing us is HTML, and HTML is tricky, because it's hierarchical. Are you required to correctly parse it? Because if you are, the task is much more difficult. Seeing that it's homework, I doubt it, so you might do enough by:
open the file and load it to memory (assuming it isn't too large - if it is, you can write into a temporary file and move it onto the original one after you've finished)
continuously use strstr to find the anchor string you need to start replacing
replace
repeat 2 and 3 until finished with file
write file back
Since it's homework I'm going with the assumption that the string can not span multiple lines. If this assumption is correct (and barring the complications with "replacing text in HTML") then:
1 Read the next line
2 Replace string and write line (to another file)
3 If not at end, goto #1
4 Win \o/
Or perhaps the teacher wants something else shrug
First of all, C is an awesome language, but is one of the most painful languages to do this type of operation in. Just had to say it.
Can you safely assume that the contents of the entire file can fit in memory? If so:
allocate buffer big enough to hold file contents
read entire file into buffer
inputPtr = 0
while(inputPtr < size of buffer) {
replacePosition = strstr(inputPtr, stringToReplace);
if (replacePosition != NULL)
writeUntil = replacePosition - 1
else
writeUntil = end of buffer
write out buffer from inputPtr to writeUntil inclusive (could be 0 bytes)
if (replacePosition == NULL) break
write out the replacement string
inputPtr = replacePosition + strlen(stringToReplace)
}
Since this is homework, I won't give you an answer but I'll point out a classic issue that trips people up.
In C, it's easiest to read a fixed byte count (you can try to do line by line but if a line is too long, that reverts to reading a fixed number of bytes). If the string you are trying to replace ends up getting split between one buffer and a second buffer:
buf1 -> "...<img src=\"/ima"
buf2 -> "ges/logo.gif\"..."
you won't be able to do a simple search replace in memory.
Are you try strcpy function for this,
Assign the url in one string and replace it by strcpy function.
You should investigate the sed command. See what it does and do something similar.
It works as a filter, so when using it to replace something in a file what you often do is capture the output into a file and then replace the old file with the new file.
You can use following program to search & replace string in a file.
int main()
{
.....
replaceIPAddress( "System.cfg", "172.16.116.157", "127.0.0.1");
.....
}
void replaceIPAddress( char * confFileName, char *text_to_find , char *text_to_replace )
{
FILE *input = fopen(confFileName, "r");
FILE *output = fopen("temp.txt", "w");
char buffer[512];
while (fgets(buffer, sizeof(buffer), input) != NULL)
{
char *pos = strstr(buffer, text_to_find);
if (pos != NULL)
{
/* Allocate memory for temporary buffer */
char *temp = calloc(
strlen(buffer) - strlen(text_to_find) + strlen(text_to_replace) + 1, 1);
/* Copy the text before the text to replace */
memcpy(temp, buffer, pos - buffer);
/* Copy in the replacement text */
memcpy(temp + (pos - buffer), text_to_replace, strlen(text_to_replace));
/* Copy the remaining text from after the replace text */
memcpy(temp + (pos - buffer) + strlen(text_to_replace),
pos + strlen(text_to_find),
1 + strlen(buffer) - ((pos - buffer) + strlen(text_to_find)));
fputs(temp, output);
free(temp);
}
else
fputs(buffer, output);
}
fclose(output);
fclose(input);
/* Rename the temporary file to the original file */
rename("temp.txt", confFileName);
}

Resources