insert text inside a line - c

I have a file pointer which I am using with fgets() to give me a complete line along with the new line in the buffer.
I want to replace 1 char and add another character before the new line. Is that possible?
For example:
buffer is "12345;\n"
output buffer is "12345xy\n"
This is the code:
buff = fgets((char *)newbuff, IO_BufferSize , IO_handle[i_inx]->fp);
nptr = IO_handle[i_inx]->fp;
if(feof(nptr))
{
memcpy((char *)o_rec_buf+(strlen((char *)newbuff)-1),"E",1);
}
else
{
memcpy((char *)o_rec_buf+(strlen((char *)newbuff)-1),"R",1);
}
As you can see I am replacing the new line here (example line is shown above).
I want to insert the text and retain the new line instead of what I am doing above.

You can't insert one character the way you want to. If you are sure the o_rec_buf has enough space, and that the line will always end in ";\n", then you can do something like:
size_t n = strlen(newbuff);
if (n >= 2)
strcpy(o_rec_buf + n - 1, "E\n");
/* memcpy(o_rec_buf+n-1, "E\n", 3); works too */
Note that using feof() like the way you do is an error most of the times. feof() tells you if you hit end-of-file condition on a file after you hit it. If you are running the above code in a loop, when feof() returns 'true', no line will be read by fgets, and buff will be NULL, but newbuff will be unchanged. In other words, newbuff will contain data from the last fgets call. You will process the last line twice. See CLC FAQ 12.2 for more, and a solution.
Finally, why all the casts? Are o_rec_buf and newbuff not of type char *?

If the buffer has enough space, you'll need to move the trailer 1 character further, using memmove and update the char you need.
Make sure you do not forget to memmove the trailing '\0'.

Related

Skipping oversized inputs when using fgets(3)

this is probably quite easy to figure out, maybe i'm just looking in the wrong places, but how does one test if fgets has read an oversized input? In the code below, i'm trying to skip further processing for empty lines and oversized ones and go straight to the next line, for empty lines it works just fine.
Printing the strlen(buffer) when using line lengths < maxsize and it gives me expected values.
However when i enter lines that exceed the maxsize, it prints a value over 9000, which should still exceed the maxsize, and therefore enter the if-clause, but this doesn't happen. I've tried casting the return value of strlen into an int, didn't work.
What am i missing here? Thanks for any replies :)
char buffer[102];
while (fgets(buffer,100,stdin)!=NULL){
size_t maxsize = 102;
printf("%ld",strlen(buffer));
if(strcmp(buffer,"\n")==0||strlen(buffer)>maxsize){
continue;
}
//further processing
}
I
in the code:
char buffer[102];
while (fgets(buffer,100,stdin)!=NULL){
You don't need to give two more characters to buffer. The parameter size of fgets just can be the application of the sizeof operator, as in:
char buffer[102];
while (fgets(buffer, sizeof buffer, stdin) != NULL) {
That will give you space for lines of up to 101 characters (to leave space to the string terminator) including (or not, see below) the new line character.
But, answering your question, I understand that you want to know what happens if your input in one line is indeed bigger that the buffer size you provided, what happens then to the input, and how fgets deal with this:
Fgets() reads as many characters as it finds a \n in the input, or the buffer fills completely (this is, after including the \0 character that it must append to the string to terminate it) So, fgets() will fill as many characters in the buffer as the buffer has, minus one, reserved for the null string terminator, and the rest of the line will be read in the next fgets() (or another call to any of the functions of the stdio package).
So, basically, lines longer than one less than the buffer size are split in pieces, in which all except the last don't actually end in a new line, and the last will have the new line included, and will be shorter, all with a length of the length you specified minus one, but the last piece, in which the length is what it requires (again, always less than or equal than the length specified minus one)

STDIN redirection: how to make program end once fgets() reads an expected ending line

Ok, so I have a program that reads lines of a file. However once it reaches the line
*** END ***
it's meant to see that
char str[100];
while(fgets(str,100,stdin) != NULL && strcmp(str,"*** END ***"))
and the while loop should stop because strcmp will be equal to 0 therefore making the while loop false.
However it doesn't. I think this is because str has a different amount of chars (I'm assuming the rest after the copied line have nothing inside of them?) than "*** END ***". How can I fix my program so that it will end once the line is read? Thanks.
OK, so I know now it's because in my example text, I had a line after that one. Once deleted it works fine. But how can I make it end whether there's a line after it or not?
you can use
char * strstr ( const char *, const char * )
A pointer to the first occurrence in str1 of the entire sequence of characters specified in str2, or a null pointer if the sequence is not present in str1.
I think your input terminates with an end of line (\n) character. fgets include that also in the string.
Try strcmp(str,"*** END ***\n") instead.

How do I properly store characters in an array using read?

I have written the following code, and I don't understand why read is not storing the characters the way I expect:
char temp;
char buf[256];
while(something)
read (in,&temp, 1);
buf[strlen(buf)] = temp;
}
If I print temp and the last place of the buf array as I am reading, sometimes they don't match up. For example maybe the character is 'd' but the array contains % or the character is 0 and the array contains .
I am reading less than 256 characters but it doesn't matter because I am printing as I am reading.
Am I missing something obvious?
Yes, you're not initializing buf -- strlen(buf) is undefined. You should initialize it like so:
buf[0] = 0;
Also, it's better to keep track of the length instead of calling strlen each iteration to avoid a Shlemiel the painter algorithm.
You should also be checking for errors in the call to read(2) -- if it returns -1 or 0, you should break out of your loop, since it means either an error occurred or you reached the end of the file/input stream.
Don't use strlen in this code. strlen relies on it's argument being a NULL terminated C string. So unless you initialize your entire buffer to 0, then this code doesn't work.
At any rate strlen isn't a good choice to use when buffering data, even if you know that you're working with printable string data, if only because strlen will traverse the string every time just to get your length.
Keep a separate counter, named e.g. numRead, only append to buf at the numRead position, and increment numRead by the amount that you read.

strlen in array

I'm debugging a code in which a .ini file is being read for the value of string called Timeout(which is taken into a varibale called rbuf).Please tell me the content of the .ini file when the condition is as follows:
if((strlen(rbuf) > 0) && (rbuf[strlen(rbuf)-1] == '\n')){
rbuf[strlen(rbuf)-1] = '\0';
}
When will the debugger go into the above if loop?
Please specify the exact content of the rbuf value (Buffer value)
When the line has a 'string length' (anything greather than 0, not counting the null-terminator) and the final char before the zero-terminator is a newline, it will enter the conditional block and set that newline to be a null terminator.
In order to tell you the exact contents of rbuf, I would need to know the contents of the ini file. But, for example, if you had a line of text in it like:
i love programming
And lets assume there is an undisplayed newline at the end if it.
Then rbuf would start off containing:
`i love programming\n\0'
Thats 20 bytes. Strlen will return 19 (not including the null-terminator at the end).
rbuf[strlen(rbuf)-1] will be the '\n' character (at index 18 in the buffer).
So your code would see that a newline is at index 18, and set it to '\0', so you end up with:
i love programming\0\0
in your buffer.
Hard to say with the information you have given, but:
(strlen(rbuf) > 0) : rbuf contains a non-empty string
(rbuf[strlen(rbuf)-1] == '\n') : rbuf contain a string that ends with a line break.
Other than that, rbuf might only contain a line break. Or it might contian a series of charecters and ends with a line break.

Using fgets to read strings from file in C

I am trying to read strings from a file that has each string on a new line but I think it reads a newline character once instead of a string and I don't know why. If I'm going about reading strings the wrong way please correct me.
i=0;
F1 = fopen("alg.txt", "r");
F2 = fopen("tul.txt", "w");
if(!feof(F1)) {
do{ //start scanning file
fgets(inimene[i].Enimi, 20, F1);
fgets(inimene[i].Pnimi, 20, F1);
fgets(inimene[i].Kood, 12, F1);
printf("i=%d\nEnimi=%s\nPnimi=%s\nKaad=%s",i,inimene[i].Enimi,inimene[i].Pnimi,inimene[i].Kood);
i++;}
while(!feof(F1));};
/*finish getting structs*/
The printf is there to let me see what was read into what and here is the result
i=0
Enimi=peter
Pnimi=pupkin
Kood=223456iatb i=1
Enimi=
Pnimi=masha
Kaad=gubkina
i=2
Enimi=234567iasb
Pnimi=sasha
Kood=dudkina
As you can see after the first struct is read there is a blank(a newline?) onct and then everything is shifted. I suppose I could read a dummy string to absorb that extra blank and then nothing would be shifted, but that doesn't help me understand the problem and avoid in the future.
Edit 1: I know that it stops at a newline character but still reads it. I'm wondering why it doesn't read it during the third string and transfers to the fourth string instead of giving the fourth string the fourth line of the source but it happens just once.
The file is formatted like this by the way
peter
pupkin
223456iatb
masha
gubkina
234567iasb
sasha
dudkina
123456iasb
fgets stops reading when it reads a newline, but the newline is considered a valid character and is included in the returned string.
If you want to remove it, you'll need to trim it yourself:
length = strlen(str);
if (str[length - 1] == '\n')
str[length - 1] = '\0';
Where str is the string into which you read the data from the file, and length is of type size_t.
To answer the edit to the question: the reason the newline is not read during the third read is because you are not reading enough characters. You give fgets a limit of 12 characters, which means it can actually read a maximum of 11 characters since it has to add the null terminator to the end.
The line you read is 11 characters in length before the newline. Note that there is a space at the end of that line when you output it:
Kood=223456iatb i=1
^
As already stated, if there's enough room in the buffer, then fgets() reads the data including the newline into the buffer and null terminates the line. If there isn't enough room in the buffer before coming across the newline, fgets() copies what it can (the length of the buffer minus one byte) and null terminates the string. The library resumes reading from where fgets() left off on the next iteration.
Don't mess with buffers smaller than 2 bytes long.
Note that gets() removes the newline (but does not protect you from buffer overflows, so do not use it). If things go as currently planned, gets() will be removed from the next version of the C standard; it will be a long time before it is removed from C libraries (it will just become a non-standard - or ex-standard - additional function available for abuse).
Your code should check each of the fgets() function calls:
while (fgets(inimene[i].Enimi, 20, F1) != 0 &&
fgets(inimene[i].Pnimi, 20, F1) != 0 &&
fgets(inimene[i].Kood, 12, F1) != 0)
{
printf("i=%d\nEnimi=%s\nPnimi=%s\nKaad=%s", i, inimene[i].Enimi, inimene[i].Pnimi, inimene[i].Kood);
i++;
}
There are places for do/while loops; they are not used very often, though.
the fgets function reads newline char as a part of the string read.
From the description of fgets:
The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, or a newline is read and transferred to s, or an end-of-file condition is encountered. The string is then terminated with a null byte.
if Enimi/Pnimi/Kood are arrays not pointers:
while( fgets(inimene[i].Enimi,sizeof inimene[i].Enimi,F1) &&
fgets(inimene[i].Pnimi,sizeof inimene[i].Pnimi,F1) &&
fgets(inimene[i].Kood,sizeof inimene[i].Kood,F1) )
{
if( strchr(inimene[i].Enimi,'\n') ) *strchr(inimene[i].Enimi,'\n')=0;
if( strchr(inimene[i].Pnimi,'\n') ) *strchr(inimene[i].Pnimi,'\n')=0;
if( strchr(inimene[i].Kood,'\n') ) *strchr(inimene[i].Kood,'\n')=0;
printf("i=%d\nEnimi=%s\nPnimi=%s\nKaad=%s", i, inimene[i].Enimi, inimene[i].Pnimi,inimene[i].Kood);
i++;
}

Resources