Проблемы с доступом к массиву struct при отправке в функцию

Я новый программист на Си, и вам придется извинить меня за отсутствие знаний. Медленно, но верно я поправляюсь. Мне интересно, почему я не могу получить доступ к членам моей структуры после того, как отправил их в функцию, которая намеревается их изменить. Эта проблема возникает в коде, показанном ниже. В основном моя программа анализирует XML-документ и ищет определенные шаблоны для извлечения текста. В моей основной функции я делаю структуру: artinfo artIn[128] = {}; который определен в моем заголовочном файле как:

#ifndef FILE_TABLE_H
#define FILE_TABLE_H
#ifdef  __cplusplus
extern "C" {
#endif
    typedef struct article_info {
        char author1[512];
        char author2[512];
        char author3[512];
        char author4[512];
        char author5[512];
        char author6[512];
        char title[2048];
        char version[4];
        char year[4];
        char page[64];
        char abstract[4096];
        char notes[4096];
} artinfo;

#ifdef  __cplusplus
}
#endif
#endif  

После создания этого экземпляра и очистки его с помощью memset я продолжаю отправлять его в другую функцию, которая будет извлекать текст и намеревается вернуть его обратно в структуру. Функция показана ниже.

bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo *artIn[]){

int isNewline;             /* Boolean indicating we've read a CR or LF */
long lFileLen;             /* Length of file */
long lIndex;               /* Index into cThisLine array */
long lLineCount;           /* Current line number */
long lLineLen;             /* Current line length */
long lStartPos;            /* Offset of start of current line */
long lTotalChars;          /* Total characters read */
char cThisLine[BUFSIZE];     /* Contents of current line */
char *cFile;                  /* Dynamically allocated buffer (entire file) */
char *cThisPtr;               /* Pointer to current position in cFile */
char cNextLine[BUFSIZE];
char buffer[BUFSIZE];
char title[] = "<text top=\"245\"";
char ending[] = "$";
char author[] = "$</text>";
bool tfound, afound;
char *match, *cNextLinePtr;
long lNextLineCount;
int i, j;

//initialize some values
tfound = false;
afound = false;
fseek(input, 0L, SEEK_END);  /* Position to end of file */
lFileLen = ftell(input);     /* Get file length */
rewind(input);               /* Back to start of file */
memset(&cThisLine,0,sizeof(cThisLine));
memset(&cNextLine,0,sizeof(cNextLine));
memset(&buffer,0,sizeof(buffer));

printf("TEST: Entered read parser\n");
cFile = calloc(lFileLen + 1, sizeof(char));
printf("TEST:\n");
if(cFile == NULL )
{
    printf("\nInsufficient memory to read file.\n");
    return 0;
}

fread(cFile, lFileLen, 1, input); /* Read the entire file into cFile */
printf("TEST: read the file in\n");
lLineCount  = 0L;
lTotalChars = 0L;

cThisPtr    = cFile;              /* Point to beginning of array */
printf("TEST: Got to here.\n");

while (*cThisPtr)                 /* Read until reaching null char */
{
    //printf("TEST: Got to here.\n");
    lIndex    = 0L;                 /* Reset counters and flags */
    isNewline = 0;
    lStartPos = lTotalChars;

    while (*cThisPtr)               /* Read until reaching null char */
    {
        if (!isNewline)               /* Haven't read a CR or LF yet */
        {
            if (*cThisPtr == CR || *cThisPtr == LF) /* This char IS a CR or LF */
            isNewline = 1;                        /* Set flag */
            //printf("Flag was set");
            //exit(0);
        }

        else if (*cThisPtr != CR && *cThisPtr != LF) /* Already found CR or LF */
            break;                                     /* Done with line */

        cThisLine[lIndex++] = *cThisPtr++; /* Add char to output and increment */
        ++lTotalChars;

    } /* end while (*cThisPtr) */

    cThisLine[lIndex] = '\0';     /* Terminate the string */
    ++lLineCount;                 /* Increment the line counter */
    lLineLen = strlen(cThisLine); /* Get length of line */
    /* THIS is where I look for the matches to the patterns for my info. */
//    printf("TEST: Printing 1 line\n%s", cThisLine);
//    exit(0);

    if(strstr(cThisLine,title)!= NULL && tfound == false)
    {
        printf("TEST: Looking for title info.\n");
        match = strstr(cThisLine,">");
        //printf("TEST: match first points to %c\n", *match);
        //exit(0);
        j = 0;
        match++;
        //printf("TEST: match points to %c\n", *match);
        while(*match!='<')
        {
            //pridntf("TEST: match is %c\n", *match);
            //printf("TEST: %c", *match);
            buffer[j] = *match;
            //printf("TEST: %c", buffer);
            j++;
            match++;
        }
        lNextLineCount = lLineCount;
        do
        {
            lNextLineCount = lNextLineCount + 1;
            readaheadone(cFile, lNextLineCount, cNextLinePtr, lbuf);
            strcpy(cNextLine, lbuf->bline);
            cNextLinePtr = cNextLine;
            printf("TEST: the current line is - %s\nthe next line is %s\n",cThisLine,cNextLine);
            //printf("TEST: Before test exit");
            //exit(0);
            if(strstr(cNextLinePtr,ending)!=NULL)
            {
                printf("TEST: Author Info spans more than 1 line.\n");
                match = strstr(cThisLine,">");
                j++; //i DON'T RESET COUNTER SO IT JUST KEEPS FILLING THE BUFFER AFTER LEAVING A SPACE
                match++;
                //printf("TEST: match points to %c\n", *match);
                while(*match!='<')
                {
                    //pridntf("TEST: match is %c\n", *match);
                    //printf("TEST: %c", *match);
                    buffer[j] = *match;
                    //printf("TEST: %c", buffer);
                    j++;
                    match++;
                }
            }

        } while(strstr(cNextLinePtr,ending)!=NULL);

    strcpy((*artIn[0]).title, buffer);
    printf("The title is: %s\n", buffer);//artinfo[0].author);
    printf("The title is: %s\n", (*artIn[0]).title);
    tfound = true;
    }

    if(strstr(cThisLine,author)!= NULL && afound == false)
    {
        printf("TEST: Looking for author info.\n");
        match = strstr(cThisLine,">");

    }

Кажется, все работает нормально, пока не достигнет: strcpy((*artIn[0]).title, buffer); а также printf("The title is: %s\n", ((*artIn[0]).title); заявления. Я всегда получаю ошибку и дамп стека - т.е. 1 [main]Parst_Text 7296 open_stackdumpfile: дамп трассировки стека в Parse_Text.exe.stackdump Я не совсем уверен, что я делаю неправильно - я думаю, что это вызов доступа к член массив struct, как будто я удаляю эти операторы, программа запускается без ошибок. Я не уверен, что просто кладу слишком много в стек или как использовать дамп стека, чтобы выяснить проблему. Все советы приветствуются, но, пожалуйста, держите их конструктивно. Благодарю. Также, пожалуйста, дайте мне знать, если я перегружен этим вопросом, так как я не был уверен, сколько деталей предоставить.

РЕДАКТИРОВАТЬ: согласно запросу здесь есть функция, которая вызывает синтаксический анализатор читателя

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>   //for close()
#include <ctype.h>    //for toupper()
#include <stdbool.h>  //for bool type
#include <errno.h>    //where the standard error is written for calls to OS
#include "file_table.h"
#define BUFSIZE 1024
#define CR 13            /* Decimal code of Carriage Return char */
#define LF 10            /* Decimal code of Line Feed char */
#define EOF_MARKER 26    /* Decimal code of DOS end-of-file marker */

void fillFileTable(char *filedir, ftable *table, bool populate, ftinfo *info);
bool readerParser(FILE *InputFile, FILE *OutputFile, textlbuf *lbuf, artinfo *artIn[]);
void readaheadone(char *cFile, long nextLineCount ,char *currentPtr, textlbuf *lbuf);

int main()
{
    /*Define variables & Instantiate Structs.*/
    ftable files[128];
    ftinfo info;
    artinfo artIn[128] = {};
    textlbuf store[1];
    char buffer[BUFSIZE];
    char dir[260] = "C:/DTEST/Parse_Text/91_1_text"; //would be better if user could enter this - fix for later
    ftinfo *fti = &info; 
    textlbuf *lbuf = &store;
    FILE *fp, *op; //fp is input file, op is output file
    int i, j, k;
    bool iReadReturn;

    /*Clear Out Memory Structures*/
    memset(&files,0,sizeof(files));
    memset(&info,0,sizeof(info));
    memset(&artIn,0,sizeof(artIn));
    memset(&buffer,0,sizeof(buffer));
    memset(&store,0,sizeof(store));

    /*Fill the File Table*/
    printf("TEST: Preparing to fill the file table...\n");
    fillFileTable(dir,files,true,fti);
    if(info.success == false)
    {
        printf("Something went wrong. Now exiting");
        exit(1);
    }
    printf("File table has been filled: %s\n",info.notes);
    printf("File table contains: %d\n", info.fileCount);
    printf("TEST: 'fillFileTable' is successful? --- %s\n", info.success?"true":"false");
    for(i=0;i<info.fileCount;i++)
    {
        if(files[i].type == 'd')
            printf("File Folder is: %s\t its size is %d\n",files[i].fileName,files[i].fileSize);
        else
            printf("File is: %s\t its size is %d\n",files[i].fileName,files[i].fileSize);
    }
    printf("\n\n");
   //printf("TESTd: Exiting after file table printout.\n\n"); exit(0);

   op=fopen("./test_Out.txt", "a");
   if (op == NULL )             /* Could not open file */
    {
        printf("Error opening output file: %s (%u)\n", strerror(errno), errno);
        return 1;
    }

    //for(i=0;i<info.fileCount;i++) //Figure out how to loop through all files - improvement for later
    fp=fopen("./91_1_text/test1.txt", "r");
    if (fp == NULL )             /* Could not open file */
    {
        printf("Error opening input file: %s (%u)\n", strerror(errno), errno);
        return 1;
    }

    iReadReturn = readerParser(fp, op, lbuf, artIn); /* Read the file and print output */
    if (iReadReturn == false)
    {
        printf("ERROR: The file did not read correctly.\n");
        exit(1);
    }
    k = fclose(fp);
    if (k != 0)
        exit(k);

    k = fclose(op);
    if (k != 0)
        exit(k);
    printf("Program Completed Successfuly.\n");
    return 0;

}

2 ответа

Решение

Уже есть много предложений о том, как вы можете улучшить надежность своего кода. Я собираюсь ответить на главную проблему, которую вы упомянули в своем оригинальном посте.

Вы сказали,

Кажется, все работает нормально, пока не достигнет: strcpy((*artIn[0]).title, buffer); а также printf("The title is: %s\n", ((*artIn[0]).title); заявления. Я всегда получаю ошибку и дамп стека - т.е. 1 [main]Parst_Text 7296 open_stackdumpfile: Dumping stack trace to Parse_Text.exe.stackdump Я не совсем уверен, что я делаю неправильно

Виновником этой проблемы является то, что у вас есть

bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo *artIn[])

но когда вы вызываете функцию, вы используете:

readerParser(fp, op, lbuf, artIn);

Я удивлен, что компилятор не пометил предупреждение или ошибку. artIn объявлен как:

artinfo artIn[128] = {};

Когда вы используете artIn при вызове функции он ухудшается до указателя типа artinfo*, Было бы хорошо, если тип аргумента аргумента artinfo* artIn или же artinfo artIn[] но нет artinfo* artIn[],

Вы должны изменить тип artIn в readerParser, как в декларации, так и в определении.

bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo artIn[])

А затем заменить все использования *artIn в этой функции только artIn,

Надеюсь это поможет.

С помощью этого объявления функции:

bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo *artIn[])

4-й аргумент будет массивом указателей на структуры artinfo, а не указателем на массив структур artinfo. Когда он пытается отменить ссылку на эти предполагаемые указатели, он терпит неудачу.

Вместо этого должно быть:

bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo (*artIn)[])

Кроме того, их исправление, по крайней мере, сделает вашу программу более надежной.

  1. Кажется, нет никакой проверки на переполнение buffer
  2. Вы не ставите явно нулевой символ в конце buffer, Несмотря на то, что вы делаете memset перед входом в цикл, если он переполнен, он не только может быть слишком длинным, но также может не завершаться нулем.
  3. Вы должны использовать strncpy вместо strcpy, в противном случае вы рискуете переполнить пространство, выделенное в строке назначения. Также, как заметил Мэтт, вы должны вручную добавить нулевой символ в конец вашей строки после вызова strncpy.
Другие вопросы по тегам