Replace a specific line in a file with a new text

The code actually works, but not as expected, it replace a line but not the line I choose, For example if I choose to replace line 2 he replace the line 3 or if I choose to replace first line it replace the line 3, it has a strange behavior, what is I'm doing wrong.. ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#include <stdio.h>
#include <windows.h>
#include <string.h>
#include <conio.h>
#include "resource.h"
#define MAX 256
#define MAXPASS 20

const char cpassnam[] = "pass.txt";

void inputData();
void retrieveData();
void modifyData();
void viewInfo();
void deleteData();

struct Info
{
    char name[50];
    char lastname[50];
    char city[50];
    char country[50];
    char tel[20];
}info;

void cgetstr(const char* prm, char* str, int csz)
{
    str[0] = 0;

    while(printf("%s", prm) && (!fgets(str, csz, stdin) || *str == 0))
    {
        puts("\n Invalid input\n");
    }
}
...
...
int main()
{
...
}
...
...
void modifyData()
{
    int temp, status;
    unsigned options;
    do
    {
        system("cls");
        printf("\n\t\t\t\tData Base\n\t\t\t\t---------");
        printf("\n\n\tSection Modify info\n\t-------------------");
        printf("\n\n\tChoose an option:\n\n");
        printf("\n   1. Modify info");
        printf("\n   2. Back to main menu");
        printf("\n\n\n   Select: ");
        status = scanf("%d", &options);

        while((temp = getchar()) != EOF && temp != '\n');
        if(!status)
        {
            printf("\n\n Invalid option.. Choose 1 or 2\a");
            Sleep(2000);
            system("cls");
            options = 0;
            continue;
        }
        else if(options == 1)
        {
            BOOL got = FALSE;
            char pass[MAXPASS] = {0};
            FILE* fs = fopen(cpassnam, "r+");

            if(fs != NULL)
            {
                got = (fgets(pass, MAXPASS, fs) != NULL && strlen(pass) > 0);
            }
            if(got)
            {
                char newpass[MAXPASS] = {0};
                system("cls");
                printf("\n\t\t\t\tData Base\n\t\t\t\t---------");
                printf("\n\n\tSection Modify info\n\t-------------------");
                cgetstr("\n\n\n   Enter existing password: ", newpass, MAXPASS);
                const int l = strlen(pass) - 2;

                if(pass[l] == '\n')
                {
                    pass[l] = 0;
                }
                if(strcmp(pass, newpass) == 0)
                {
                    FILE *fptr1, *fptr2;
                    int lNo, lineCtr = 0;
                    char str[MAX], fName[MAX];
                    char newLn[MAX], temp[] = "temp.txt";

                    printf("\n\n\n\n\t\t\t     Access  Granted\n");
                    Sleep(1500);
                    system("cls;");
                    printf("\n\t\t\t\tData Base\n\t\t\t\t---------");
                    printf("\n\n Replace old info");
                    printf("\n\n Input the file name to be opened : ");
                    fgets(fName, MAX, stdin);
                    fName[strlen(fName) - 1] = '\0';
                    fptr1 = fopen(fName, "r");
                    while(1)
                    {
                        if(!fptr1)
                        {
                            printf("\n\n Unable to open the input file\n\a");
                            Sleep(1000);
                            printf("\n\n ..returning to menu");
                            Sleep(1500);
                            break;
                        }
                        fptr2 = fopen(temp, "w");
                        if(!fptr2)
                        {
                            printf("Unable to open a temporary file to write\n");
                            Sleep(2000);
                            fclose(fptr1);
                        }
                        printf("\n\n Update the old info:");
                        printf("\n\n\n\tName:       ");
                        scanf("%49s", info.name);
                        printf("\n\n\tLast name:  ");
                        scanf("%49s", info.lastname);
                        printf("\n\n\tCity:       ");
                        scanf("%49s", info.city);
                        printf("\n\n\tCountry:    ");
                        scanf("%49s", info.country);
                        printf("\n\n\tPhone:      ");
                        scanf("%19s", info.tel);
                        fprintf(fptr2, "%s %s %s %s %s\n",
                            info.name, info.lastname, info.city, info.country, info.tel);
                        fgets(newLn, MAX, stdin);
                        printf("\n\n Input the line number you want to replace : ");
                        scanf("%d", &lNo);
                        lNo++;
                        while (!feof(fptr1))
                            {
                                strcpy(str, "\0");
                                fgets(str, MAX, fptr1);
                                if (!feof(fptr1))
                                {
                                    lineCtr++;
                                    if (lineCtr != lNo)
                                        {
                                            fprintf(fptr2, "%s", str);
                                        }
                                        else
                                        {
                                            fprintf(fptr2, "%s", newLn);
                                        }
                                    }
                            }
                        fclose(fptr1);
                        fclose(fptr2);
                        remove(fName);
                        rename(temp, fName);
                        printf("\n\n\n\n\t\t\t Replacement successfully..!");
                        Sleep(2000);
                        break;
                    }
                }
                else
                {
                    puts("\n\n   Wrong password\a");
                    Sleep(1000);
                    printf("\n\n\n\n\t\t\t      Access Denied\n");
                    Sleep(1500);
                }
            }
            else
            {
                if(fs != NULL)
                {
                    fclose(fs);
                }
                fs = fopen(cpassnam, "w");
                system("cls");
                printf("\n\t\t\t\tData Base\n\t\t\t\t---------");
                printf("\n\n\n\n To modify information, requires a password.");
                cgetstr("\n\n Register new password: ", pass, MAXPASS);
                fprintf(fs, "%s\n", pass);
                printf("\n\n Password saved to data base");
                Sleep(2000);
                system("cls");
            }
            fclose(fs);
        }
        else if(options == 2)
        {
            printf("\n\n\n ..returning to main menu");
            Sleep(2000);
            system("cls");
        }
        else
        {
            printf("\n\n Invalid option.. Choose 1 or 2\a");
            Sleep(2000);
            system("cls");
        }
    }while(options != 2);
}
Last edited on
First: You should at least [re]set lineCtr = 0; after line 65. It seems that loop doesn't make sense anyway?

Second: What are you trying to do on line 97? Do you mean lNo--;? Since the user enters 1 based line number while lineCtr is 0 based?
I just needed for my program and I search an example on the web I found this:
https://www.w3resource.com/c-programming-exercises/file-handling/c-file-handling-exercise-9.php and I update it for my code..
Last edited on
This is where you develop your debugging skills! Being able to debug a program is a skill that all programmers need to acquire. When a program is not working as expected then you use the debugger to step through the code and see the contents of the variables. When the trace and/or variables are not as expected then you're found the problem!

For:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
lNo++;
                        while (!feof(fptr1))
                            {
                                strcpy(str, "\0");
                                fgets(str, MAX, fptr1);
                                if (!feof(fptr1))
                                {
                                    lineCtr++;
                                    if (lineCtr != lNo)
                                        {
                                            fprintf(fptr2, "%s", str);
                                        }
                                        else
                                        {
                                            fprintf(fptr2, "%s", newLn);
                                        }
                                    }
                            }


This can be re-coded more concisely (not tried):

1
2
for (int lineCtr = 1; fgets(str, MAX, fptr1) != NULL; ++lineCtr)
	fprintf(fptr2, "%s", lineCtr != Lno ? str : newLn);


assuming line numbers start at 1.
Last edited on
The piece of the code that refers the question is this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#define MAX 256

void modifyData()
{
	FILE *fptr1, *fptr2;
	int lNo, lineCtr = 0;
	char str[MAX], fName[MAX];
	char newLn[MAX], temp[] = "records.txt";
	
	printf("\n\n Replace old contact");
	printf(" Input the file name to be opened : ");
	fgets(fName, MAX, stdin);
	fName[strlen(fName) - 1] = '\0';
	fptr1 = fopen(fName, "r");
	if(!fptr1)
	{
		printf("Unable to open the input file\n");
	}
	fptr2 = fopen(temp, "w");
	if(!fptr2)
	{
		printf("Unable to open a temporary file to write\n");
		fclose(fptr1);
	}
	printf(" Update the old info");
	fgets(newLn, MAX, stdin);
	printf(" Input the line no you want to replace : ");
    scanf("%d", &lNo);
	lNo++;
	while (!feof(fptr1)) 
        {
            strcpy(str, "\0");
            fgets(str, MAX, fptr1);
            if (!feof(fptr1)) 
            {
                lineCtr++;
                if (lineCtr != lNo) 
                    {
                        fprintf(fptr2, "%s", str);
                    } 
                    else 
                    {
                        fprintf(fptr2, "%s", newLn);
                    }
                }
        }
        fclose(fptr1);
        fclose(fptr2);
        remove(fName);
        rename(temp, fName);
        printf(" Replacement successfully..!");
}


I only modify it a bit to fit my program

here:
1
2
printf(" Update the old info");
fgets(newLn, MAX, stdin);


I add this:
1
2
3
4
5
6
7
8
9
10
11
12
printf("\n\n\n\tName:       ");
scanf("%49s", info.name);
printf("\n\n\tLast name:  ");
scanf("%49s", info.lastname);
printf("\n\n\tCity:       ");
scanf("%49s", info.city);
printf("\n\n\tCountry:    ");
scanf("%49s", info.country);
printf("\n\n\tPhone:      ");
scanf("%19s", info.tel);
fprintf(fptr2, "%s %s %s %s %s\n",
           info.name, info.lastname, info.city, info.country, info.tel);


the rest of it its the same.
Last edited on
I tried your code seeplus, and I replace the line 2, then I open the records.txt and I saw the change made in the file, it has changed as that line I want but I still need to modify something cause the line I modify the code fill it in the first line then the very first line become the second and the 2nd line becomes the 3rd and that third line is a void line so this is how the file is modify:

Before:

1
2
3
bnm bnm bnm bnm 124567890
asdf rewq zxcv mnbv 1234567890
dfgh dfgh dfgh dfgh 129876540


After:

1
2
3
4
Gang Sang Mang Lang 0123789456
bnm bnm bnm bnm 124567890

dfgh dfgh dfgh dfgh 129876540
Last edited on
The problem with substitute is not a problem as the 5th line after is modify becomes the first and so on.. The only problem I want to resolve is the void line between the records.
Debug, debug, debug........

For file line replacement, consider this test progam:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>

int main()
{
	FILE *fi, *fo;

	char data[256];
	char newdata[256];

	int newlno;

	fi = fopen("data1.txt", "r");
	fo = fopen("data1.new", "w");

	for (int lno = 1; fgets(data, 255, fi) != NULL; )
		printf("%i) %s", lno++, data);

	fseek(fi, 0, SEEK_SET);

	printf("New text: ");
	fgets(newdata, 255, stdin);

	printf("Line to replace: ");
	scanf("%i", &newlno);

	for (int lineCtr = 1; fgets(data, 255, fi) != NULL; ++lineCtr)
		fprintf(fo, "%s", lineCtr != newlno ? data : newdata);

	fclose(fo);

	fo = fopen("data1.new", "r");

	for (int lno = 1; fgets(data, 255, fo) != NULL; )
		printf("%i) %s", lno++, data);

	fclose(fi);
	fclose(fo);
}


This works OK with Windows using your before data. If this works OK on your system with the data (check the file names!!), then there is a difference between this type of code and yours. If this test code doesn't work on your system then you probably have an issue with an extra \n (or \r) somewhere which you'll need to track down.
Last edited on
Ok I'll try this first, but I was up to ask you about the fseek function SEEK_SET is the begining of the file. Is SEEK_CUR set the position of the file pointer, could anyhow help me to set the new line to the position of the line I want to replace or refers to a different thing ?
Last edited on
With fseek() and SEEK_CUR, you can set the file position to a specified value. Then depending upon the open mode, you can read/write from that position. If you write then this overwrites data starting at the specified position. If the length of what you write is less than what was there before, then part of the previous data will still be there. If it's greater, then you overwrite that data that came after.

If you have:


abc
def
ghi


and you set the file position to the beginning of def, and write z then you get:


abc
zef
ghi


and if you write qwerty then you get:

abc
qwertyhi


as the line terminating chars after def are overwritten together with the g of the next line.

If you write z\n then you probably get (depending upon line terminating chars):


abc
z

ghi


as the line terminating char(s) following z overwrite the existing e & f which then leaves the existing line terminators.

This is probably not what you want.

Only if you replace text with new text that is the same length does this method do what is probably expected.
Last edited on
Yup, you're right ... I tried your first code
test program
, I edit few lines for "data1.new", then I ran and I substitute line 2 and then line 3 and is working perfectly as expect to modify and overwrite the line I wanted to. Now I have to think about how to adapt it on my code..
As always my brain is overflows and I'm not putting my mind to work and again seeplus is my helping hand, BUT.. but it seems I always learn something every time a problem is solved and I fell happy as I understand the mechanism and the logic of why is done like this and lots of functions I do not know much about them, as I'm still a beginner and I'll longer still a beginner, I really have to thank you for your help and for your patience, as NOT everyone has it.

Until the next time Cheers :)
Last edited on
You're welcome. We were all beginners at some point. When code doesn't work as expected, one important aspect - apart from fixing it! - is to understand why it isn't working as expected. Then you learn.

Cheers! :)
Topic archived. No new replies allowed.