Stucking about strcpy at C - c

I Couldn't understand this code i've left comment line about strcopy. Can you explain it to me? Thanks already. I'm new at c and trying to improve myself. Sometimes i stuck at somewhere and in this situation i couldn't find any solution.
#include <stdio.h>
#include <string.h>
#define SIZE 1000
int main(){
int lwd,cnt;
char read1[SIZE];
char true;
FILE *r = fopen("test.txt","r");
if(r==NULL){
printf("Er.");
}
FILE *cpy =fopen("temp","w");
if(cpy==NULL){
printf("Er.");
fclose(r);
}
printf("Please enter whic line you wanna remove:");
scanf("%d",&lwd);
while(!feof(r)){
strcpy(read1,"\0"); // what does it mean?
fgets(read1,SIZE,r);
if(!feof(r)){
cnt++;
if(cnt != lwd){
fprintf(cpy,"%s",read1);
}
}
}
fclose(r);
fclose(cpy);
remove("test.txt");
rename("temp","test.txt");
FILE *read;
read = fopen("test.txt","r");
if(read == NULL){
printf("Error.");
fclose(read);
}
true=fgetc(read);
while(true != EOF){
printf("%c",true);
true=fgetc(read);
}
getch();
return 0;
}

The statement
strcpy(read1,"\0");
is just copying an empty string to initialize read1.
It's a silly way to do it; read1[0] = 0; is just as good, but as #chux points out in the comments, initializing read1 isn't necessary, and there are other things wrong with the code (e.g., checking result of fgets).

You can see the documentation for the strcpy below.
https://i.stack.imgur.com/AN38r.png
You can see the strcpy copies the second string argument in the first string argument. The first argument is the destination where the string is copied. The second argument is the source from which the complete string is copied.
Therefore we can say that the strcpy line is just to ensure that read1 is always empty before the reading the next line.
If we skip this line then a case where the length of the previously read line is more than the current line can give errors.
It is almost a redundant step here as fgets replaces the '\n' with '\0'. Thus, characters after that do not matter.

Related

Displaying lines with given number of characters

I have written such a program which suppose to returns lines which are containing at least 11 characters and 4 digits. I messed up something with types of variables I guess but I cant figure out how should I fix it.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main()
{
char line[200];
char *temp[200];
int i = 0, k=0;
printf("Enter a string: \n");
while(fgets(line, sizeof(line),stdin))
{
int numberAlpha = 0;
int numberDigit = 0;
int i;
for(i=0; i<strlen(line); i++){
if(isalpha(line[i])) numberAlpha++;
else if(isdigit(line[i])) numberDigit++;
}
if(numberAlpha+numberDigit>10 && numberDigit>3){
temp[i]=line;
i++;
}
}
while(temp[k]!='\0'){
printf("%s", temp[k]);
k++;
}
return 0;
}
You're reusing the same buffer each time, and you're storing a pointer to that buffer in your temp array. What you're going to end up with is a bunch of the same pointer in that array, with that pointer pointing at the last line in the file.
What you can do instead is to rewrite your temp[i]=line statement to the following:
temp[i] = malloc(sizeof(line))
memcpy(temp[i], line, sizeof(line))
In so doing, you'll be creating a new array with the contents of the matching line, which won't get overwritten when you come around and read the next line out of the file.
Note that, because you're allocating that on the heap, at the end of your function you'll want to free it:
while (temp[k] != '\0') {
printf(...);
free(temp[k]);
k++
}
As said before , one issue is with copying of
temp[i]=line;
This can be solved by doing a new heap allocation and doing memcopy to temp.
The other issue that i could see is - with the value of variable i. Then temp array will always be assigned to strlen(line) index. You might be thinking of storing in the temp array from 0. Which is not happening.
This can be solved by-
int start_index=0;
while(...){
if(numberAlpha+numberDigit>10 && numberDigit>3){
temp[start_index]=line;
start_index++;
}
}
The problem is you are assigning the same address here:
temp[i]=line;
and line is used in the loop to read as well. That means it's overwritten in every iteration.
Instead, you can use strdup() (POSIX function):
temp[i] = strdup(line);
to copy the lines you are interested in. If strdup() not available you can use malloc() + strcpy() to do the same. Plus, free() them later.
In addition, be aware that:
fgets() will read in the newline character if there's room in the buffer which may not be what you want. So, you need to trim it out. You can do it with:
line[strcspn(line, "\n")] = 0; /* trim the trailing newline, if any */
The arguments to isalpha() and isdigit() should be cast to unsigned char to avoid potential undefined behaviour i.e. these two lines:
if(isalpha(line[i])) numberAlpha++;
else if(isdigit(line[i])) numberDigit++;
should be
if(isalpha((unsigned char)line[i])) numberAlpha++;
else if((unsigned char)isdigit(line[i])) numberDigit++;

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);

How to save every line in file (IN C) in a variable? :)

I need to save every line of text file in c in a variable.
Here's my code
int main()
{
char firstname[100];
char lastname[100];
char string_0[256];
char string[256] = "Vanilla Twilight";
char string2[256];
FILE *file;
file = fopen("record.txt","r");
while(fgets(string_0,256,file) != NULL)
{
fgets(string2, 256, file);
printf("%s\n", string2);
if(strcmp(string, string2)==0)
printf("A match has been found");
}
fclose(file);
return 0;
}
Some lines are stored in the variable and printed on the cmd but some are skipped.
What should I do? When I tried sscanf(), all lines were complete but only the first word of each line is printed. I also tried ffscanf() but isn't working too. In fgets(), words per line are complete, but as I've said, some lines are skipped (even the first line).
I'm just a beginner in programming, so I really need help. :(
You're skipping over the check every odd number of lines, as you have two successive fgets() calls and only one strcmp(). Reduce your code to
while(fgets(string_0,256,file) != NULL)
{
if( ! strcmp(string_0, string2) )
printf("A match has been found\n");
}
FWIW, fgets() reads and stores the trailing newline, which can cause problem is string comparison, you need to take care of that, too.
As a note, you should always check the return value of fopen() for success before using the returned pointer.

Array of strings being overwritten

I have a program that is trying to take a text file that consists of the following and feed it to my other program.
Bruce, Wayne
Bruce, Banner
Princess, Diana
Austin, Powers
This is my C code. It is trying to get the number of lines in the file, parse the comma-separated keys and values, and put them all in a list of strings. Lastly, it is trying to iterate through the list of strings and print them out. The output of this is just Austin Powers over and over again. I'm not sure if the problem is how I'm appending the strings to the list or how I'm reading them off.
#include<stdio.h>
#include <stdlib.h>
int main(){
char* fileName = "Example.txt";
FILE *fp = fopen(fileName, "r");
char line[512];
char * keyname = (char*)(malloc(sizeof(char)*80));
char * val = (char*)(malloc(sizeof(char)*80));
int i = 0;
int ch, lines;
while(!feof(fp)){
ch = fgetc(fp);
if(ch == '\n'){ //counts how many lines there are
lines++;
}
}
rewind(fp);
char* targets[lines*2];
while (fgets(line, sizeof(line), fp)){
strtok(line,"\n");
sscanf(line, "%[^','], %[^',']%s\n", keyname, val);
targets[i] = keyname;
targets[i+1] = val;
i+=2;
}
int q = 0;
while (q!=i){
printf("%s\n", targets[q]);
q++;
}
return 0;
}
The problem is with the two lines:
targets[i] = keyname;
targets[i+1] = val;
These do not make copies of the string - they only copy the address of whatever memory they point to. So, at the end of the while loop, each pair of target elements point to the same two blocks.
To make copies of the string, you'll either have to use strdup (if provided), or implement it yourself with strlen, malloc, and strcpy.
Also, as #mch mentioned, you never initialize lines, so while it may be zero, it may also be any garbage value (which can cause char* targets[lines*2]; to fail).
First you open the file. The in the while loop, check the condition to find \n or EOF to end the loop. In the loop, if you get anything other than alphanumeric, then separate the token and store it in string array. Increment the count when you encounter \n or EOF. Better use do{}while(ch!=EOF);

Use of getdelim

#include <stdio.h>
#include <stdlib.h>
main() {
FILE *fp;
char *lineptr = NULL;
size_t len;
size_t read;
fp = fopen("test.txt", "r");
if(NULL == fp) {
exit(1);
}
while((read = getdelim(&lineptr, &len, 33, fp)) != -1) {
printf("%s", lineptr);
}
free(lineptr);
}
In test.txt I have written:
before giving tab !after tab has been given
I have set ! as the delimiter but I don't see any difference between getline and getdelim in getdelim I can set the delimter but in case of getline it is newline character, I want the o/p to be:
before giving tab
after tab has been given
! should be taken as delimiter. How can I do this using getdelim?
This is not tested, but try to change your printf line, so you can see the difference:
printf("%s\n",lineptr);
It's doing exactly what you think it is, it's just that the first string it prints is
before giving tab !
with no new line, followed by after tab has been given
change your print to
printf("%s\n",lineptr);
It's working perfectly fine (and delimiting on '!' as you requested); the only problem is that you are printing out the individual strings exactly as they come in, in a while loop.
Remember: getdelim includes the delimiter in the string (it won't remove the '!' for you).
For the given test case, the first time around the loop will give the string "before giving tab !", and the second time around the loop will give the string "after tab has been given". You are printing them both out without any newlines or anything, so your output looks just the same as the input. I suggest you print a newline after each string, but that won't get rid of the '!'. So you may want to change your print code to:
while((read=getdelim(&lineptr,&len,33,fp))!= -1)
{
if (lineptr[strlen(lineptr)-1] == '!')
lineptr[strlen(lineptr)-1] = '\0';
printf("%s\n",lineptr);
}
char before[256], after[256];
fscanf(fp, "%255[^!]!%255[^\n]", before, after);
printf("%s\n%s", before, after);
See man getdelim. The delim is included in the string, followed by a null character. If you want to print a string followed by an EOL, puts is the fastest way.
puts(lineptr);
If you also want to remove the delim '!', add this before the puts.
lineptr[read - 1] = 0;

Resources