简体   繁体   中英

I want to separate the read chain from the file in C

I am trying to separate the string

"CristinaRodriguezRiveraComputacion210302414RamiroSilvaPerezIndustrial217890453PatriciaDuranSanchezCivil215643525RaulColinGranadosComputacion215678342"

read from a file but when I separate and print this string, the following is not being separated correctly:

在此处输入图像描述

Required output:

Cristina Rodríguez Rivera Computación 210302414 //simulating that each string is inside a block of 15 bytes

I don't know what's wrong with the code, I've been trying to figure out if my logic is wrong for a while

#include <stdio.h>
#include <errno.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>

typedef struct{
   char name[15];
   char father[15];
   char mother[15];
   char degree[15];
   char id[15];
}Student;


Student al;

int main(){

    FILE*  ent = fopen("DatosEntrada.txt","r");
    FILE*  sal = fopen("longitud.txt","a");

    if(ent != NULL){

        char name[15];
        char father[15];
        char mother[15];
        char degree[15];
        char id[15];

        fseek(ent, 0, SEEK_END);  //getting file length
        int longarch = ftell(ent);
        rewind(ent); //go back to the start

        char dinamic[longarch];

        fscanf(ent,"%s",&dinamic);

        int longitud =  strlen(dinamic);


        int contador=0,iterador=0;
        for(int i=0;i<longarch;i++){

            if( isupper(dinamic[i]) ){

                    if( islower(dinamic[i-1])  && islower(dinamic[i+1])  ){
                        iterator=0;
                        counter++; 

                    }


                    if(counter== 0){ //name
                        iterator=0;
                        name[iterator] = dinamic[i];
                         //printf("%c",name[iterator]);
                        iterator++;

                    }else if(counter== 1){ //father

                        father[iterator] = dinamic[i];
                        //printf("%c",father[iterator] );
                        iterator++;

                    }else if(counter== 2){  //mother

                        mother[iterator] = dinamic[i];
                        //printf("%c",mother[iterator]);
                        iterator++;

                    }else if(counter== 3){  //degree

                        degree[iterator] = dinamic[i];
                        //printf("%c",degree[iterator]);
                        iterator++;

                    }

            }else if( islower(dinamic[i])  ){

                    if(counter== 0){ //name

                        name[iterator] = dinamic[i];
                        //printf("%c",name[iterator]);
                        iterator++;

                    }else if(counter== 1){  //father

                        father[iterator] = dinamic[i];
                        //printf("%c",father[iterator]);
                        iterator++;

                    }else if(counter== 2){ //mother

                        mother[iterator] = dinamic[i];
                        //printf("%c",mother[iterator]);
                        iterator++;

                    }else if(counter== 3){ //degree

                        degree[iterator] = dinamic[i];
                        //printf("%c",degree[iterator]);
                        iterator++;

                    }

            }else if( isdigit(dinamic[i])  ){

                    if( islower(dinamic[i-1]) && isdigit(dinamic[i+1]) ){
                        iterator=0;
                        counter++;

                    }else if(   isupper(dinamic[i+1]) && isdigit(dinamic[i-1]) ){

                        id[iterator] = dinamic[i];

                        //printf("%c",id[iterator]);

                        counter=0;

                        printf("(%s,%s,%s,%s,%s)\n",name,father,mother,degree,id);
                        strcpy(al.name,name);
                        strcpy(al.father,father);
                        strcpy(al.mother,mother);
                        strcpy(al.degree,degree);
                        strcpy(al.id,id);

                        fwrite(&al,sizeof(Student), 1, sal);


                    }

                    if(counter== 4){  //id

                        id[iterator] = dinamic[i];
                       // printf("%c",id[iterator]);
                        iterator++;

                    }

            }

        }


        fclose(ent);
        fclose(sal);

    }else{

       fprintf(stdout, "ERROR: %s", strerror(errno));
    }


}

I think the key problem here is that you aren't terminating the fields with NUL ( \0 ) after copying characters into them.

Consider your first field, nombre . You write data to it on two different lines. But you never write \0 to it anywhere. The data you copy into the field is Cristina , which is 8 characters, so the remaining 7 characters of the field just contain whatever happened to be in memory. When you call printf you get Cristina , but there's no \0 , so printf just keeps going and prints whatever, until it finds a \0 that's there by coincidence.

So when you detect the end of a field, you need to add a \0 before moving on to the next field.

There are other issues, though. One is here:

        for(int i=0;i<longarch;i++){

            if( isupper(dinamico[i]) ){

                    if( islower(dinamico[i-1])  && islower(dinamico[i+1])  ){
                        iterador=0;
                        contador++; 

                    }

Consider what happens the first time through the loop, when i == 0 . The isupper call will return true, because the first character of your data is uppercase. It will then execute the next line, which does islower(dianamico[i-1]) to see if the previous character was lowercase. But i == 0 here, so this is accessing the byte before the start of your buffer. You need to avoid this check when i == 0 .

You also repeat the code to copy a character into each line twice. You only need to do it once. Your code should look something like:

while (there is more data) {
  if (it's the start of a new field) {
    add \0 to the end of the current field;
    iterador = 0;
    contador++;
  }
  copy character into current field;
  iterator++;
}
add \0 to the end of the last field;

I tried out your program and got the extraneous data in the printout. However, when the five work fields were initialized to zeros, ensuring that valid character terminators were in place, the data appeared clean. Following, is the additional code added to ensure the strings contained the data you want.

        if(ent != NULL)
    {

        char nombre[15];
        char Paterno[15];
        char Materno[15];
        char carrera[15];
        char matricula[15];

        for (int x=0; x < 15; x++) /* Work field initialization */
            {
            nombre[x] = '\0';
            Paterno[x] = '\0';
            Materno[x] = '\0';
            carrera[x] = '\0';
            matricula[x] = '\0';
        }

Give that a try.

I'm glad your code now seems to work.

However, if it were me, I'd make the code a bit more modular.

I'd also use a state machine/variable to simplify the code.

Also, it makes sense to actually read in the data and save it to an array of Alumno structs.

Here is the refactored code. It is annotated:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>

#ifdef DEBUG
#define dbgprt(_fmt...)     printf(_fmt)
#else
#define dbgprt(_fmt...)     do { } while (0)
#endif

#define ALLMODE(_cmd) \
    _cmd(NAME) \
    _cmd(FATHER) \
    _cmd(MOTHER) \
    _cmd(CAREER) \
    _cmd(DATE)

#define ENUM(_sym)      MODE_##_sym,
enum {
    ALLMODE(ENUM)
    MODE_MAX
};

#define TAG(_sym)   [MODE_##_sym] = #_sym,
char *tags[MODE_MAX] = {
    ALLMODE(TAG)
};

typedef struct {
    char nombre[15];
    char apPat[15];
    char apMat[15];
    char carrera[15];
    char matricula[15];
} Alumno;

Alumno al;

int icur;                           // current index into dinamico
char *dinamico;                     // buffer for entire file contents

// getstring -- fill in a struct field
void
getstring(char *field)
{
    char *out = field;
    int chr;

    // get and save first char
    chr = dinamico[icur++];
    dbgprt("getstring: FIRST chr='%c'\n",chr);
    *out++ = chr;

    // do we want:
    //   0 -- Cristina
    //   1 -- 210302414
    int dateflg = isdigit(chr);

    while (1) {
        // look at next character
        chr = dinamico[icur];
        if (chr == 0)
            break;
        dbgprt("getstring: PEEK chr='%c'\n",chr);

        int isdig = isdigit(chr);

        // we want a date -- stop if char is _not_ a digit
        if (dateflg) {
            if (! isdig)
                break;
        }

        // we want a name -- stop if char is upper (start of new name) or
        // is a digit (start of a date)
        else {
            if (isupper(chr))
                break;
            if (isdig)
                break;
        }

        *out++ = chr;
        ++icur;
    }

    *out = 0;

    dbgprt("getstring: field='%s'\n",field);
}

int
main(void)
{

    FILE *ent = fopen("DatosEntrada.txt", "r");
    FILE *sal = fopen("longitud.txt", "w");

    if (ent == NULL) {
        fprintf(stdout, "ERROR: %s", strerror(errno));
        return 1;
    }

    // get size of file
    fseek(ent, 0, SEEK_END);
    int longarch = ftell(ent);
    rewind(ent);                    // go back to the start

    // get buffer for entire file
    dinamico = malloc(longarch + 1);
    fscanf(ent, "%s", dinamico);
    longarch = strlen(dinamico);

    int state = MODE_NAME;

    // empty list
    Alumno *list = NULL;
    int count = 0;

    // current record
    Alumno *rec = NULL;

    for (icur = 0; icur < longarch;) {
        if (dinamico[icur] == '\n')
            break;

        dbgprt("main: STATE state=%d (%s)\n",state,tags[state]);

        switch (state) {
        case MODE_NAME:
            // increase size of list
            list = realloc(list,sizeof(*list) * (count + 1));
            rec = &list[count];
            ++count;

            getstring(rec->nombre);
            state = MODE_FATHER;
            break;

        case MODE_FATHER:
            getstring(rec->apPat);
            state = MODE_MOTHER;
            break;

        case MODE_MOTHER:
            getstring(rec->apMat);
            state = MODE_CAREER;
            break;

        case MODE_CAREER:
            getstring(rec->carrera);
            state = MODE_DATE;
            break;

        case MODE_DATE:
            getstring(rec->matricula);
            state = MODE_NAME;
            printf("%s %s %s %s %s\n",
                rec->nombre,rec->apPat,rec->apMat,rec->carrera,rec->matricula);
            fwrite(rec, sizeof(Alumno), 1, sal);
            break;
        }
    }

    fclose(ent);
    fclose(sal);

    free(dinamico);
    free(list);

    return 0;
}

There are many ways to achieve your objective. I offer this as a working example that outputs both the version in parenthesis and shows how a 'record' (15 chars wide * 5) can be accumulated (for display or storage)...

My hope is that this will provide material to learn more about another way to reach your goal.

void showFlds( char flds[][15], int n ) {
    printf( "****\n" );
    for( int i = 0; i < n; i++ )
        printf( "'%-15s'\n", flds[i] );
    printf( "****\n" );
}

int main() {
    char *in =
        "CristinaRodriguezRiveraComputacion210302414"
        "RamiroSilvaPerezIndustrial217890453"
        "PatriciaDuranSanchezCivil215643525"
        "RaulColinGranadosComputacion215678342";

    const int nFlds = 5;
    int fldCnt = 0;
    char fldCopys[5][15];
    int cCnt = 0;

    putchar( '(' );
    bool firstDig = true;
    for( char *cp = in; *cp; cp++ ) {
        if( cp > in && ( isupper( *cp ) || ( isdigit( *cp ) && firstDig ) ) ) {
            fldCopys[ fldCnt++ ][ cCnt ] = '\0';
            if( fldCnt < nFlds ) {
                putchar( ' ' );
            } else {
                printf( ")\n" );
                showFlds( fldCopys, fldCnt );
                putchar( '(' );
                fldCnt = 0;
            }
            cCnt = 0;
        }
        putchar( *cp );
        fldCopys[ fldCnt ][ cCnt++ ] = *cp;
        firstDig = !isdigit( *cp );
    }
    printf( ")\n" );
    fldCopys[ fldCnt++ ][ cCnt ] = '\0';
    showFlds( fldCopys, fldCnt );
    return 0;
}

Output:

(Cristina Rodriguez Rivera Computacion 210302414)
****
'Cristina       '
'Rodriguez      '
'Rivera         '
'Computacion    '
'210302414      '
****
(Ramiro Silva Perez Industrial 217890453)
****
'Ramiro         '
'Silva          '
'Perez          '
'Industrial     '
'217890453      '
****
(Patricia Duran Sanchez Civil 215643525)
****
'Patricia       '
'Duran          '
'Sanchez        '
'Civil          '
'215643525      '
****
(Raul Colin Granados Computacion 215678342)
****
'Raul           '
'Colin          '
'Granados       '
'Computacion    '
'215678342      '
****

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM