Проблемы с доступом к массиву 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)[])
Кроме того, их исправление, по крайней мере, сделает вашу программу более надежной.
- Кажется, нет никакой проверки на переполнение
buffer
- Вы не ставите явно нулевой символ в конце
buffer
, Несмотря на то, что вы делаете memset перед входом в цикл, если он переполнен, он не только может быть слишком длинным, но также может не завершаться нулем. - Вы должны использовать strncpy вместо strcpy, в противном случае вы рискуете переполнить пространство, выделенное в строке назначения. Также, как заметил Мэтт, вы должны вручную добавить нулевой символ в конец вашей строки после вызова strncpy.