How to find and replace a position in a text file with an element in an array in C?

I have two text files data.txt and template.txt. I read and shared the data in the data.txt file and saved it as an array. My problem is to use this data in the template.txt file, find the $ sign and use any number that follows the indicator for the array in customerData.

data.txt

Public|Jane|Q|Ms.|600|Maple Street|Your Town|Iowa|12345 Penner|Fred|R|Mr.|123|that Street|Winnipeg|MB|R3T 2N2 Gardner|Mark|E|Mr.|76|The Avenue|Toronto|ON|M5W 1E6 Acton|Hilda|P|Mrs.|66|What Blvd|Winnipeg|MB|R3T 2N2 

template.txt

 Welcome back, $1! We hope that you and all the members of the $0 family are constantly reminding your neighbours there on $5 to shop with us. As usual, we will ship your order to $3 $1 $2. $0 $4 $5 $6, $7 $8 

The result should be something like this:

 Welcome back, Jane! We hope that you and all the members of the Public family are constantly reminding your neighbors there on Maple Street to shop with us. As usual, we will ship your order to Ms. Jane Q. Public 600 Maple Street Your Town, Iowa 12345 

I wrote the code, but my brain was stuck in using position in the array for template.txt. I need help on how to do this in C? Any input would be appreciated.

 #include <stdio.h> #include <string.h> #include <stdlib.h> #define INPUT_LENGTH 128 #define FIELD_LENGTH 30 #define NUM_FIELDS 9 int main( int argc, char *argv[] ) { FILE *template = NULL; FILE *data = NULL; char input[INPUT_LENGTH]; char customerData[NUM_FIELDS][FIELD_LENGTH]; int element = 0; char *next; char ch; template = fopen( "template.txt", "r" ); if ( template != NULL ) { // read in the customers until we're done data = fopen( "data.txt", "r" ); if ( data != NULL ) { while(fgets(input, INPUT_LENGTH,data) != NULL){ next = strtok(input, "|"); //splitting the data stored in input by | while(next != NULL){ strcpy(customerData[element],next); printf("%s\n", customerData[element] ); //prints the first element in the array next =strtok(NULL, "|"); element++; while((ch=fgetc(template)) != NULL){ if(ch == '0'){ }else if(ch == '1'){ }else if(ch == '2'){ //do sth }else if(ch == '3'){ }else if(ch == '4'){ }else if(ch == '5'){ }else if(ch == '6'){ }else if(ch == '7'){ }else if(ch == '8'){ }else if(ch == '9'){ } } /*while(fgets(input, INPUT_LENGTH,template) != NULL){ for(int i=0; i< strlen(input); i++){ ch= strchr(template, "$") ch = input[INPUT_LENGTH]; if(ch != "$"){ if(ch == "0"){ printf("%s\n", hi ); } } } }*/ } } fclose( data ); } fclose( template ); } return EXIT_SUCCESS; } 
+5
source share
4 answers

I know this post is old, but I ran into the same problem and I am going to share my code for future readers. Here is how I did it. I did not need to complicate anything. After parsing the data and saving it to customerData you can do something similar to superimpose the data on the array indices by reading each character.

  rewind( template ); while ( fgets( input, INPUT_LENGTH, template ) != NULL ) { // Process the input one character at a time looking for variables to replace with customerData element = 0; ch = input[element]; while(ch) { if(ch != '$') { printf("%c", ch); } else { element++; ch = input[element]; printf("%s", customerData[atoi( &ch)]); } element++; ch = input[element]; } } printf("\n"); 
+1
source

There are various solutions to this problem. All of them can be simplified by breaking the problem into several auxiliary functions that will help keep the program logic straight. (note: this is true for any part of the code, but it is especially true for this bit of code).

Data processing to collect information associated with each client can be processed by the struct members contained for each field. (while each field may be narrower in size, your size is 30 fine) For example, by declaring a constant for FLDSZ = 30 , you can create a structure for your information similar to:

 typedef struct { char last[FLDSZ]; char first[FLDSZ]; char mi[FLDSZ]; char sal[FLDSZ]; char street[FLDSZ]; char streetno[FLDSZ]; char city[FLDSZ]; char state[FLDSZ]; char zip[FLDSZ]; } sp; 

(Ideally, you would like to dynamically allocate some initial number of pointers to a struct, fill in and realloc as needed. For this example, the static number contained in the array is excellent)

To start storing your data, you need a way to split the line into various tokens. strtok perfect here. You just need to read each line, tokenize and save the resulting line as the correct member. With an array of structures, you also need to track a separate index of the structure in addition to coding the way to store individual tokens as the correct member. It is here that the first auxiliary function can make life easier. For example, your complete reading / filling of the data structure can be done using something similar to:

 char buf[MAXC] = {0}; sp s[MAXS]; .... while (fgets (buf, MAXC, ifp)) { /* read each line of data */ char *p; size_t idx = 0; /* tokenize/save in struct 's[n]' */ for (p = strtok (buf, "|"); p; p = strtok (NULL, "|\n")) { fillsp (&s[n], p, &idx); /* assign to correct member */ } if (++n == MAXS) { /* limit reached */ fprintf (stderr, "MAXS structs filled.\n"); break; } } 

(where ifp is the input file stream pointer and n your structure index)

Helper function fillsp is key. It takes a struct sp address, a pointer to the current token, and a pointer to the current idx member index. Based on the idx value, through either the if-then-else line, or better, the switch , you can coordinate the correct member with each token. Something similar to the following fits here:

 /* store 'p' in correct stuct 's' member based on index 'idx' */ void fillsp (sp *s, const char *p, size_t *idx) { switch (*idx) { case 0 : strncpy (s->last, p, FLDSZ); if (s->last[FLDSZ - 1] != 0) s->last[FLDSZ - 1] = 0; (*idx)++; break; case 1 : strncpy (s->first, p, FLDSZ); if (s->first[FLDSZ - 1] != 0) s->first[FLDSZ - 1] = 0; (*idx)++; break; case 2 : s->mi[0] = s->mi[1] = 0; *(s->mi) = *p; (*idx)++; break; case 3 : strncpy (s->sal, p, FLDSZ); if (s->sal[FLDSZ - 1] != 0) s->sal[FLDSZ - 1] = 0; (*idx)++; break; case 4 : strncpy (s->streetno, p, FLDSZ); if (s->streetno[FLDSZ - 1] != 0) s->streetno[FLDSZ - 1] = 0; (*idx)++; break; case 5 : strncpy (s->street, p, FLDSZ); if (s->street[FLDSZ - 1] != 0) s->street[FLDSZ - 1] = 0; (*idx)++; break; case 6 : strncpy (s->city, p, FLDSZ); if (s->city[FLDSZ - 1] != 0) s->city[FLDSZ - 1] = 0; (*idx)++; break; case 7 : strncpy (s->state, p, FLDSZ); if (s->state[FLDSZ - 1] != 0) s->state[FLDSZ - 1] = 0; (*idx)++; break; case 8 : strncpy (s->zip, p, FLDSZ); if (s->zip[FLDSZ - 1] != 0) s->zip[FLDSZ - 1] = 0; (*idx)++; break; default : fprintf (stderr, "error: index outside allowed 0-8.\n"); exit (EXIT_FAILURE); } } 

(note: idx updated when the correct case is found. The default case warns of an invalid index, but you should also add strlen checks in addition to forced nul termination).

After saving your data, the next task is to simply read the template file and replace the '$X' format placeholder with the appropriate field from your structure. One thing you need to know about is that after each reading you will need to rewind the file-pointer template ( 'tfp' ) so that it is used again for the next client. The auxiliary function helps here again. The logic for displaying welcome information for each client can be simple:

 for (i = 0; i < n; i++) /* show welcome for each */ welcome (&s[i], tfp); 

(note: in fact, you would look at the clientโ€™s name and then just pass that address to the welcome function, but in this example each will be printed)

When parsing each line of a template in the welcome function, strchr provides a simple way to both check and find any '$' in any given line. Using a pair of character pointers, you can easily scroll through each line and find / replace each format specifier. To create the actual line for output, you can use strcat and strncat . For example, for welcome you can use something similar to the following:

 void welcome (sp *s, FILE *tfp) { char buf[MAXC] = {0}; while (fgets (buf, MAXC, tfp)) { char *p = buf, *ep; char obuf[MAXC] = {0}; while (*p && (ep = strchr (p, '$'))) { strncat (obuf, p, ep++ - p); strcat (obuf, rtnmemb (s, *ep++ - '0')); p = ep; } strcat (obuf, p); printf ("%s", obuf); /* relies on trailing '\n' from read */ } putchar ('\n'); rewind (tfp); } 

The last helper function used by welcome , rtnmemb used to return the element indicated by the character following '$' . (note: since you are reading the number as a character, you need to subtract '0' from the ASCII value to hide it to a numerical value.) The rtnmemb implementation may look like this:

 /* return correct member of struct 's' based on 'idx' */ char *rtnmemb (sp *s, size_t idx) { switch (idx) { case 0 : return s->last; break; case 1 : return s->first; break; case 2 : return s->mi; break; case 3 : return s->sal; break; case 4 : return s->streetno; break; case 5 : return s->street; break; case 6 : return s->city; break; case 7 : return s->state; break; case 8 : return s->zip; break; default : printf ("error: requested member outside allowed 0-8.\n"); } return NULL; } 

Combining all the pieces of the puzzle, you can do something like:

 #include <stdio.h> #include <stdlib.h> #include <string.h> /* constants (file size, max struct, max char) */ enum { FLDSZ = 30, MAXS = 64, MAXC = 128 }; typedef struct { char last[FLDSZ]; char first[FLDSZ]; char mi[FLDSZ]; char sal[FLDSZ]; char street[FLDSZ]; char streetno[FLDSZ]; char city[FLDSZ]; char state[FLDSZ]; char zip[FLDSZ]; } sp; void fillsp (sp *s, const char *p, size_t *idx); char *rtnmemb (sp *s, size_t idx); void welcome (sp *s, FILE *tfp); int main (int argc, char **argv) { char buf[MAXC] = {0}; sp s[MAXS]; size_t i, n = 0; /* input, template, output streams */ FILE *ifp = argc > 1 ? fopen (argv[1], "r") : stdin; FILE *tfp = fopen (argc > 2 ? argv[2] : "../dat/template.txt", "r"); FILE *ofp = argc > 3 ? fopen (argv[3], "w") : stdout; if (!ifp || !tfp || !ofp) { /* validate streams open */ fprintf (stderr, "error: file open failed.\n"); return 1; } while (fgets (buf, MAXC, ifp)) { /* read each line of data */ char *p; size_t idx = 0; /* tokenize/save in struct 's[n]' */ for (p = strtok (buf, "|"); p; p = strtok (NULL, "|\n")) { fillsp (&s[n], p, &idx); } if (++n == MAXS) { /* limit reached */ fprintf (stderr, "MAXS structs filled.\n"); break; } } for (i = 0; i < n; i++) /* show welcome for each */ welcome (&s[i], tfp); if (ifp != stdin) fclose (ifp); /* close files */ if (ofp != stdout) fclose (ofp); fclose (tfp); return 0; } /* store 'p' in correct stuct 's' member based on index 'idx' */ void fillsp (sp *s, const char *p, size_t *idx) { switch (*idx) { case 0 : strncpy (s->last, p, FLDSZ); if (s->last[FLDSZ - 1] != 0) s->last[FLDSZ - 1] = 0; (*idx)++; break; case 1 : strncpy (s->first, p, FLDSZ); if (s->first[FLDSZ - 1] != 0) s->first[FLDSZ - 1] = 0; (*idx)++; break; case 2 : s->mi[0] = s->mi[1] = 0; *(s->mi) = *p; (*idx)++; break; case 3 : strncpy (s->sal, p, FLDSZ); if (s->sal[FLDSZ - 1] != 0) s->sal[FLDSZ - 1] = 0; (*idx)++; break; case 4 : strncpy (s->streetno, p, FLDSZ); if (s->streetno[FLDSZ - 1] != 0) s->streetno[FLDSZ - 1] = 0; (*idx)++; break; case 5 : strncpy (s->street, p, FLDSZ); if (s->street[FLDSZ - 1] != 0) s->street[FLDSZ - 1] = 0; (*idx)++; break; case 6 : strncpy (s->city, p, FLDSZ); if (s->city[FLDSZ - 1] != 0) s->city[FLDSZ - 1] = 0; (*idx)++; break; case 7 : strncpy (s->state, p, FLDSZ); if (s->state[FLDSZ - 1] != 0) s->state[FLDSZ - 1] = 0; (*idx)++; break; case 8 : strncpy (s->zip, p, FLDSZ); if (s->zip[FLDSZ - 1] != 0) s->zip[FLDSZ - 1] = 0; (*idx)++; break; default : fprintf (stderr, "error: index outside allowed 0-8.\n"); exit (EXIT_FAILURE); } } /* return correct member of struct 's' based on 'idx' */ char *rtnmemb (sp *s, size_t idx) { switch (idx) { case 0 : return s->last; break; case 1 : return s->first; break; case 2 : return s->mi; break; case 3 : return s->sal; break; case 4 : return s->streetno; break; case 5 : return s->street; break; case 6 : return s->city; break; case 7 : return s->state; break; case 8 : return s->zip; break; default : printf ("error: requested member outside allowed 0-8.\n"); } return NULL; } void welcome (sp *s, FILE *tfp) { char buf[MAXC] = {0}; while (fgets (buf, MAXC, tfp)) { char *p = buf, *ep; char obuf[MAXC] = {0}; while (*p && (ep = strchr (p, '$'))) { strncat (obuf, p, ep++ - p); strcat (obuf, rtnmemb (s, *ep++ - '0')); p = ep; } strcat (obuf, p); printf ("%s", obuf); } putchar ('\n'); rewind (tfp); } 

Output

 $ ./bin/str_template ../dat/data.txt Welcome back, Jane! We hope that you and all the members of the Public family are constantly reminding your neighbours there on Maple Street to shop with us. As usual, we will ship your order to Ms. Jane Q. Public 600 Maple Street Your Town, Iowa 12345 Welcome back, Fred! We hope that you and all the members of the Penner family are constantly reminding your neighbours there on that Street to shop with us. As usual, we will ship your order to Mr. Fred R. Penner 123 that Street Winnipeg, MB R3T 2N2 Welcome back, Mark! We hope that you and all the members of the Gardner family are constantly reminding your neighbours there on The Avenue to shop with us. As usual, we will ship your order to Mr. Mark E. Gardner 76 The Avenue Toronto, ON M5W 1E6 Welcome back, Hilda! We hope that you and all the members of the Acton family are constantly reminding your neighbours there on What Blvd to shop with us. As usual, we will ship your order to Mrs. Hilda P. Acton 66 What Blvd Winnipeg, MB R3T 2N2 

Look at the approach to the problem. It is often useful to replace a long chain of if-then-else statements with a switch . Both are acceptable, and this applies to any of the different approaches to your problem. While any approach correctly processes the data, it is readable and quite effective and provides the correct conclusion, in the end it is a matter of taste. Let me know if you have any questions regarding the approach.

+3
source

I think this can be done easier:

 #include <stdio.h> #include <string.h> #include <stdlib.h> #define FLDMAX 30 // docust -- process single customer line void docust(FILE *ftmpl,char *buf) { int fldcnt; char *bp; char *cp; int chr; int prev; char *fields[FLDMAX]; fputc('\n',stdout); // split customer line into fields fldcnt = 0; bp = buf; while (1) { cp = strtok(bp,"|"); bp = NULL; if (cp == NULL) break; fields[fldcnt++] = cp; if (fldcnt >= FLDMAX) break; } rewind(ftmpl); // output the form letter prev = EOF; while (1) { chr = fgetc(ftmpl); if (chr == EOF) break; prev = chr; // output ordinary char if (chr != '$') { fputc(chr,stdout); continue; } // get field designator (eg $3) chr = fgetc(ftmpl); // point to correct customer field chr -= '0'; if (chr >= fldcnt) continue; cp = fields[chr]; fputs(cp,stdout); } // malformed template file (eg has no newline at end) if (prev != '\n') fputc('\n',stdout); } int main(int argc,char **argv) { FILE *ftmpl; FILE *fcust; char *cp; char buf[5000]; fcust = fopen("data.txt","r"); ftmpl = fopen("template.txt","r"); while (1) { cp = fgets(buf,sizeof(buf),fcust); if (cp == NULL) break; cp = strchr(buf,'\n'); if (cp != NULL) *cp = 0; docust(ftmpl,buf); } fclose(fcust); fclose(ftmpl); return 0; } 

UPDATE:

Here is a version that is closer to what I will do for the production class application. This is mainly based on Peter's comments below.

 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> typedef unsigned int u32; // check for value within a given range #define RANGE(_val,_lo,_hi) \ (((_val) >= (_lo)) && ((_val) <= (_hi))) #define FLDMAX 30 // maximum number of fields // all options #define OPTALL(_cmd) \ _cmd(ERRSPLIT,0,"too many fields in customer record") \ _cmd(ERRSYN,1,"malformed $x in template") \ _cmd(ERRFIELD,2,"template $x too large") \ _cmd(ERRNL,3,"template missing final newline") \ _cmd(BADMONEY,4,"malformed money amount") // define option symbols #define _OPTDEF(_sym,_val,_reason) \ OPT_##_sym = 1u << ((_val) + 16), enum { OPTALL(_OPTDEF) }; #define OPTMSK 0xFFFF0000 #define OPTVAL 0x0000FFFF // option control struct opt { u32 opt_val; // option value const char *opt_tag; // option name const char *opt_reason; // option explanation }; // option table #define _OPTGEN(_sym,_val,_reason) \ { .opt_val = OPT_##_sym, .opt_tag = #_sym, .opt_reason = _reason }, struct opt opt_table[] = { OPTALL(_OPTGEN) { . opt_tag = NULL } }; // abort #define sysfault(_fmt...) \ do { \ fprintf(stderr,_fmt); \ exit(1); \ } while (0) // xfopen -- open file FILE * xfopen(const char *file,const char *mode) { FILE *xf; xf = fopen(file,mode); if (xf == NULL) sysfault("xfopen: unable to open '%s' -- %s\n",file,strerror(errno)); return xf; } // xfclose -- close file FILE * xfclose(FILE *xf) { if (xf != NULL) { fclose(xf); xf = NULL; } return xf; } // showerr -- show errors void showerr(u32 err) { struct opt *opt; err &= OPTMSK; if (err != 0) { for (opt = opt_table; opt->opt_tag != NULL; ++opt) { if (err & opt->opt_val) fprintf(stderr,"showerr: %s -- %s\n", opt->opt_tag,opt->opt_reason); } sysfault("showerr: aborting ...\n"); } } // getfld -- get field designator // RETURNS: field number (-1 means malformed (eg $X)) int getfld(FILE *ftmpl) { int chr; int acc; // assume malformed acc = -1; while (1) { chr = fgetc(ftmpl); if (chr == EOF) break; if (! RANGE(chr,'0','9')) { ungetc(chr,ftmpl); break; } if (acc < 0) acc = 0; acc *= 10; chr -= '0'; acc += chr; } return acc; } // domoney -- output a monetary amount // RETURNS: error mask u32 domoney(FILE *fout,FILE *ftmpl) { int chr; int cents; u32 opt; opt = 0; fputc('$',fout); // get dollars while (1) { chr = fgetc(ftmpl); if (chr == EOF) { opt |= OPT_BADMONEY; break; } fputc(chr,fout); if (chr == '.') break; // got something like "$$23x" if (! RANGE(chr,'0','9')) { opt |= OPT_BADMONEY; break; } } // get cents for (cents = 1; cents <= 2; ++cents) { if (opt != 0) break; chr = fgetc(ftmpl); // got something like "$$23." if (chr == EOF) { opt |= OPT_BADMONEY; break; } fputc(chr,fout); // got something like "$$23.x" if (! RANGE(chr,'0','9')) { opt |= OPT_BADMONEY; break; } } return opt; } // dosplit -- split customer line into fields // RETURNS: number of fields (-1=overflow) int dosplit(char **fields,char *buf) { int fldcnt; char *bp; char *cp; fldcnt = 0; bp = buf; while (1) { cp = strtok(bp,"|"); bp = NULL; if (cp == NULL) break; fields[fldcnt++] = cp; if (fldcnt > FLDMAX) { fldcnt = -1; break; } } return fldcnt; } // docust -- process single customer line // RETURNS: options u32 docust(FILE *fout,FILE *ftmpl,char *buf) { int chr; int prev; int fldcnt; int fldidx; int fldused; char *cp; char *fields[FLDMAX]; u32 opt; opt = 0; fldidx = 0; fldused = -1; // split customer line into fields fldcnt = dosplit(fields,buf); if (fldcnt < 0) opt |= OPT_ERRSPLIT; rewind(ftmpl); fputc('\n',fout); // output the form letter prev = EOF; while (1) { chr = fgetc(ftmpl); if (chr == EOF) break; prev = chr; // output ordinary char if (chr != '$') { fputc(chr,fout); continue; } // check for '$$' for literal '$' for money designator // NOTE: this is vast overkill, based on the problem description chr = fgetc(ftmpl); if (chr == '$') { opt |= domoney(fout,ftmpl); continue; } ungetc(chr,ftmpl); // get field designator (eg $3) fldidx = getfld(ftmpl); // malformed designator (eg $X) if (fldidx < 0) { opt |= OPT_ERRSYN; continue; } // point to correct customer field if (fldidx >= fldcnt) { opt |= OPT_ERRFIELD; continue; } cp = fields[fldidx]; // remember the largest field index we actually use if (fldidx > fldused) fldused = fldidx; fputs(cp,fout); } // malformed template file (eg has no newline at end) // technically an error but we can handle it if (prev != '\n') { fputc('\n',fout); opt |= OPT_ERRNL; } opt |= fldused; return opt; } // check_tmpl -- validate form letter template file // RETURNS: the maximum field index used by the template file int check_tmpl(FILE *fout,FILE *ftmpl) { int fldidx; char *bp; u32 err; char buf[5000]; bp = buf; for (fldidx = 0; fldidx < FLDMAX; ++fldidx) bp += sprintf(bp,"|fld%d",fldidx); err = docust(fout,ftmpl,buf + 1); showerr(err); // the maximum index we actually used fldidx = err & OPTVAL; return fldidx; } // check_cust -- validate customer entries void check_cust(FILE *fout,FILE *fcust,int fldused) { int fldcnt; u32 err; char *cp; char buf[5000]; char *fields[FLDMAX]; rewind(fcust); err = 0; while (1) { cp = fgets(buf,sizeof(buf),fcust); if (cp == NULL) break; cp = strchr(buf,'\n'); if (cp != NULL) *cp = 0; fldcnt = dosplit(fields,buf); if (fldcnt < 0) err |= OPT_ERRSPLIT; if (fldcnt != (fldused + 1)) err |= OPT_ERRFIELD; showerr(err); } } // main -- main program int main(int argc,char **argv) { FILE *ftmpl; FILE *fcust; FILE *fout; int fldused; char *cp; char buf[5000]; fcust = xfopen("data.txt","r"); ftmpl = xfopen("template.txt","r"); // pre-validate input files fout = xfopen("/dev/null","w"); fldused = check_tmpl(fout,ftmpl); check_cust(fout,fcust,fldused); fout = xfclose(fout); rewind(fcust); while (1) { cp = fgets(buf,sizeof(buf),fcust); if (cp == NULL) break; cp = strchr(buf,'\n'); if (cp != NULL) *cp = 0; docust(stdout,ftmpl,buf); } fcust = xfclose(fcust); ftmpl = xfclose(ftmpl); return 0; } 

Peter's comments:

But +1 in order to be the only answer for implementing a reasonable table lookup instead of wasting code on a switch

If a problem was stated that allowed us to designate polynomial fields (for example, $10 ), this would be obvious to everyone. In the updated code, this is implemented in getfld . But, in the original, I just took it for simplifying the decision

Are you sure if (chr >= fldcnt) ? Or maybe you assume that there are no non-localized '$' characters in the input, such as $A

Yes. In the original, it was only necessary to verify that the field number was too large, and not to check for a distorted field pointer such as $X

Based on a simple statement of the problem, we can assume that the template is well formed. For production code, we need to check this, as I did with check_tmpl , check_cust et. et al. But note how much extra code is required for a really thorough check [and this can be done in even more detail].

Or maybe set things up so that $$ prints one $ to allow a currency like $15.25

Fair enough. This is a bit overkill based on the statement of the problem, but [just to show that it can be done] I added it to domoney

If the test fails, type $c literally if there is no replacement for it.

No. If we find an invalid pointer, we want it to be a tough mistake. If the template file is incorrect, we want to interrupt, and not print millions of letters of the form with errors. So I added the check_tmpl function.

The cost of paper and postage [or the cost of email or instant messaging] for sending bad emails can be huge. Not to mention the damage to the company's reputation.

Since the client file is similar to a database, we can and should perform strict checks, because, presumably, the database entry has already been pre-checked.

The program will be interrupted if any client record is distorted. Clarification will consist in simply pointing out and skipping bad customer records, but it depends on what kind of "policy" the company will have available for such situations.

+1
source

Okay .. you should do something similar to this:

  element++; } /* finish processing ONE line and gather all array /* open the file now. not before */ template = fopen( "template.txt", "r" ); while((ch=fgetc(template)) != NULL){ if ( ch == '$' ) { char next=fgetc(template)); if ( next == '1' ) { printf("%s ",customerData[1]); ... } else { printf("%c",ch); /* just print as it is */ } printf("\n"); fclose(template); /*process next line in outer while loop */ 

If you understand this, you can do the following in the future: (i) read the template file only once in a long line (char [300]) and reuse it with for (i=0;i<strlen(template_string);i++) .

(ii) You can understand that "9" - "0" will cause int 0, "8" - "3" will lead to int 5. Thus, you can use int col = next - '0'; printf("%s ", customerData[col]) int col = next - '0'; printf("%s ", customerData[col]) (as Barmer said)

good luck to you.

-1
source

Source: https://habr.com/ru/post/1241677/


All Articles