Assign global struct variable outside main And Inside main - c

the problem is when I separated the code into the different function and this happens
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
//------Options -- change only true / false to trigger the function
bool hard_trace = false;
bool trace = true;
/*-------------------*/
//---------Defines----------
#define MAXSIZE 100 // maximum size of the characters in txt file to be buffed
/*----------------------*/
//---------Structs-----------
struct Matrix
{
char *A[10];
int depth;
};
/*--------------------------*/
//-----Variable----------
//-- global
char *B[3];
//- struct
struct Matrix matrixs ; // create new global struct
//-
//--
/*-----------------------*/
int convertCharToNumber(char target[1])
{
int numbered = target[0] - 48;
return numbered;
}
int generateDataFromFile(){
//-- temped
int currentLine = 1;
int currentRow = 0;
//-----------------
FILE *fp;
char line[MAXSIZE];
fp = fopen("test.txt", "r");
if (fp == NULL)
{
fprintf(stderr, "%s\n", "Error reading from file");
exit(EXIT_FAILURE);
}
while (fgets(line, MAXSIZE, fp) != NULL)
{
if(hard_trace){ // if it was enabled
printf("current line : %d and length : %d\n", currentLine, strlen(line));
}
if (line[strlen(line) - 1] == '\n') // cutout the \n to make the txt easy to use
{
line[strlen(line) - 1] = '\0';
}
//appileToStruct(line,currentRow);
matrixs.A[currentRow] = line;
//if(trace) printf("%s\n", line);
currentLine++; currentRow++;
}
if(trace) printf("Total line receive from txt file : %d\n" , currentLine-1); //if it was enabled
fclose(fp);
// ----------- assign the var
matrixs.depth = currentLine - 1;
//----------------------------
//return 1;
}
void main(){
generateDataFromFile();
printf("Total : %d TXT : [%s]", strlen(matrixs.A[0]), matrixs.A[0]);
}
and the output here
Total line recieve from txt file : 3
Total : 10 TXT : []
.
But it's fine when i directly put the code in the main like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
//------Options -- change only true / false to trigger the function
bool hard_trace = false;
bool trace = true;
/*-------------------*/
//---------Defines----------
#define MAXSIZE 100 // maximum size of the characters in txt file to be buffed
/*----------------------*/
//---------Structs-----------
struct Matrix
{
char *A[10];
int depth;
};
/*--------------------------*/
//-----Variable----------
//-- global
char *B[3];
//- struct
struct Matrix matrixs; // create new global struct
//-
//--
/*-----------------------*/
int convertCharToNumber(char target[1])
{
int numbered = target[0] - 48;
return numbered;
}
int main()
{
//-- temped
int currentLine = 1;
int currentRow = 0;
//-----------------
FILE *fp;
char line[MAXSIZE];
fp = fopen("test.txt", "r");
if (fp == NULL)
{
fprintf(stderr, "%s\n", "Error reading from file");
exit(EXIT_FAILURE);
}
while (fgets(line, MAXSIZE, fp) != NULL)
{
if (hard_trace)
{ // if it was enabled
printf("current line : %d and length : %d\n", currentLine, strlen(line));
}
if (line[strlen(line) - 1] == '\n') // cutout the \n to make the txt easy to use
{
line[strlen(line) - 1] = '\0';
}
//appileToStruct(line,currentRow);
matrixs.A[currentRow] = line;
//if(trace) printf("%s\n", line);
currentLine++;
currentRow++;
}
if (trace)
printf("Total line recieve from txt file : %d\n", currentLine - 1); //if it was enabled
fclose(fp);
// ----------- assign the var
matrixs.depth = currentLine - 1;
//----------------------------
printf("Total : %d TXT : [%s]", strlen(matrixs.A[0]), matrixs.A[0]);
}
OUTPUT
Total line receive from txt file : 3
Total : 10 TXT : [0000111100]
Can you guy explain to me why that the first code is not working i mean why the %s in printf doesn't show the output for me and how can i get the first code to be work

When you do this:
matrixs.A[currentRow] = line;
You're assigning the address of the local array line to an element of matrixs.A. In the case of the second program, it prints a valid value because line in still in scope. But in the first program line is out of scope so matrixs.A[0] points to invalid memory. Dereferencing this pointer invokes undefined behavior.
Also, in the second program, you may notice that every element of matrixs.A contains the last value you read. That is again because you're storing the address of line in each one.
You should instead make a copy of the string you read and save a pointer to the new string. That way 1) you're not storing the address of a local variable, and 2) you don't store the same address in every element of matrixs.A.
matrixs.A[currentRow] = strdup(line);

That's why: matrixs.A[currentRow] = line;.
line is local to the function in the first case. This statement assigned pointer, it doesn't copy the strings (you should use strncpy instead and don't forget to allocate the required memory space by malloc), so when everything is in the main(), line is well defined in that scope so matrixs.A[0] is a pointer to the existing line while in the first case line is local array which belongs to generateDataFromFile().
When you try to print matrixs.A[0] from main() (in the first case), you invoke undefined behavior because you are performing stack violation and trying to access some address on the stack which may contain whatever you want at that point of the flow execution.
Proposed fix:
// instead of matrixs.A[currentRow] = line
size_t lineSize = strlen(line)+1;
matrixs.A[currentRow] = malloc(lineSize);
strncpy(matrixs.A[currentRow], line, lineSize);
And don't forget to free() the allocated memory at the end.

Related

Using a struct and dynamically allocated memory to write all the lines from a text file in C

I have written a program in C to represent a quiz game. Each question is an individual line of a text file. I am using a struct to represent the array of questions. It begins by taking some user input, then counts the amount of text lines in the file. It then allocated the amount of memory needed for the structs before reading each line of the file into the struct. When I print out the elements in the struct it prints out 20 lines of errors instead of the file values. What am I doing incorrectly? I have included a screenshot of some of lines of the file also.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define filepath "Questions_Answers"
#define CAPACITY 120
typedef struct
{
char* questions;
} Lines;
int setupGame(int *difficulty);
int main() {
int difficulty; //Set difficulty out of ten of the quiz
int numberOfLines = 0; //Set the number of lines counted in the file initially to zero
int question_length;
char answer[20];
char c;
//Calls setup game function which sets the difficulty
difficulty = setupGame(&difficulty);
FILE* fPointer = fopen(filepath, "r"); //Points to the address of a File not yet known
//If the file has no content, print error and end program
if (fPointer == NULL) {
perror("Error opening file");
return -1;
}
// Extract characters from file and store in character c
for (c = getc(fPointer); c != EOF; c = getc(fPointer)) {
if (c == '\n') // Increment count if this character is newline
numberOfLines++;
}
numberOfLines = numberOfLines + 1;
printf("Number of questions in quiz - %d\n", numberOfLines);
Lines *lines = malloc(sizeof(Lines) * numberOfLines); // allocate memory for questions
for (int i = 0; i < numberOfLines; i++) {
int lengthOfQuestion = 150;
lines[i].questions = malloc(sizeof(char) * (lengthOfQuestion + 1));
fscanf(fPointer, "%s", lines[i].questions);
printf("%s\n", lines[i].questions);
}
fclose(fPointer);
for (int i = 0; i < numberOfLines; i++) {
free(lines[i].questions);
}
free(lines);
return 0;
}
You have to fclose(fPointer); then reopen before you want to get questions from the file.
fclose(fPointer);
fPointer = fopen("input.txt", "r");
fscanf reads word by word not whole the line. You should use fgets() or getline().
I see in your code, you init the length of all questions by 150
int lengthOfQuestion = 150;
So, i think, it's easier when you declare the struct (you can use pointer if you want):
typedef struct
{
char questions[150];
} Lines;
You should use one loop for storing and increasing the number of lines. The code will be more readable. For example:
char line[150];
lines = malloc(sizeof(Lines));
if(!lines) {// handle the error}
while (fgets(fPointer, sizeof(line), line)) {
strcpy(lines[numberOfLines].question, line);
numberOfLines++;
lines = realloc(lines, sizeof(Lines) * numberOfLines);
if(!line) {// handle the error}
}

How to compare string from file and stdin string

I need to make program that checks if string inputted from console matches any string from input file and in my case it only works if i enter string that's last line in input file and i dont know why
int n;
char c[20];
char broj[20];
FILE* input;
input = fopen("input.txt", "r");
scanf("%s", broj);
while(fgets(c, 200, input) != NULL)
{
if(strcmp(c, broj) == 0)
printf("%s", c);
}
printf("\n");
fclose(input);
return 0;
As some have pointed out, you are reading too much into your buffer.
I really do not like to see the use of sizeof operator when calculating buffer sizes as the results can change depending on context.
void printSizeofTest1(char *test1) {
printf("Size of test1: %d\n", sizeof(test1));
}
int main() {
char *test = NULL;
char test1[10] = { 0 };
char test2 = '\0';
printf("Size of test: %d\n", sizeof(test));
printf("Size of test1: %d\n", sizeof(test1));
printf("Size of test2: %d\n", sizeof(test2));
printSizeofTest1(test1);
return 0;
}
Size of test: 4
Size of test1: 10
Size of test1: 1
Size of test1: 4
And you see this often when copying and pasting code.
Instead, it's far better to define the length of your pointers as macro expressions and always add a NULL byte pad for signed chars. And never reference it via sizeof but via the macro. This also means that if you need to change the size of the buffer, you only need to change it in one place.
With regards to your question. It's difficult without seeing the input file, however, when you use fgets it's going to pull back any new line ending characters, which may not necessary represent your input.
#include <stdio.h>
#include <string.h>
#define BUFF_SIZE 20
int main() {
char c[BUFF_SIZE+1] = { 0 },
broj[BUFF_SIZE+1] = { 0 };
FILE *input = fopen("input.txt", "r");
if(NULL != input) { /* <- Test for NULL file pointer */
scanf("%20s", broj); /* <- Provide a width specifier to avoid buffer overflow */
while(fgets(c, BUFF_SIZE, input) != NULL) {
printf("Searching for: %s\nFound: %s\n", broj, c);
if(strcmp(c, broj) == 0)
printf("%s", c);
memset(c, '\0', BUFF_SIZE); /* <- Clear buffer to ensure consistent search results */
}
fclose(input);
input = NULL; /* <- Assign to NULL so that you can check to see if it's closed */
}
printf("\n");
return 0;
}
In this example, I never find the contents of my file because my search is looking for a new line character which does not exist in my search string.
Instead, you should:
Remove the new line encodings from the file
Ignore the new line encodings
Search for precisely what you are looking for

C - Can't store file into an array of strings (based off line break)

I'm pretty new to C and someone "challenged" me to try and create a sorting program using C. I come from languages that are higher-level where doing something like this is easier, but I guess the lower-level intricacies are way over my head. I haven't implemented the sorting yet, because I've ran across an obstacle (just one of many) along the way.
Anyways, here is the code I have so far:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *unsortedFile; /* prepare file variable */
char lineBuffer[100]; /* prepare variable for each line */
char *listOfLines[100]; /* prepare line array variable to be sorted */
int n = 0;
int i;
if (argc == 2) /* if a file has been given */
{
unsortedFile = fopen(argv[1], "r"); /* open it readonly */
if (unsortedFile == NULL) /* if it couldn't open */
{
printf("Couldn't open the file %s\n", argv[1]);
printf("Does it exist?\n");
return -1; /* stop the program here, return non-zero for error */
}
printf("original file:\n\n");
while (fgets(lineBuffer, sizeof(lineBuffer), unsortedFile))
{
printf("%s", lineBuffer);
listOfLines[n] = lineBuffer; /* store line buffer to the array */
n = ++n; /* increase n for the next array element */
}
printf("\nLines to be sorted: %d\n", n);
for (i = 0; i < n; i++)
{
printf("%s", listOfLines[i]);
}
} else /* if no or too many args provided */
{
printf("\nArgument error - you either didn't supply a filename\n");
printf("or didn't surround the filename in quotes if it has spaces\n\n");
return -1; /* return non-zero for error */
}
}
At this point, you're probably busy vomiting over the messiest spaghetti code you've ever seen... but anyways, the issue occurs with that while statement, I guess. The original file prints to the console fine, but I don't think each line is being stored to listOfLines.
Here is what's in file.txt, the file I am supplying as an argument to the program:
zebra
red
abacus
banana
And here is the output of the program:
dustin#DESKTOP-033UL9B:/mnt/c/Users/Dustin/projects/c/sort$ ./sort file.txt
original file:
zebra
red
abacus
banana
Lines to be sorted: 4
banana
banana
banana
banana
dustin#DESKTOP-033UL9B:/mnt/c/Users/Dustin/projects/c/sort$
Looks like the last line of the file is the only one being stored to listOfLines? What could cause this behavior?
Thanks in advance!
listOfLines is an array of pointers. All those pointers are set to point to lineBuffer:
listOfLines[n] = lineBuffer;
And lineBuffer is repeatedly overwritten by lines from the file. The last line is banana, which is the final value of lineBuffer.
Your code then prints the values in listOfLines, which are all pointers to lineBuffer.
This line is very wrong, by the way (it has undefined behavior):
n = ++n;
If you want to increment n, that's either
n = n + 1;
or
++n;
Basically, don't modify the same variable twice within the same statement.
You need an array of char arrays (not array of pointers)
Switched:
char *lineOfLines[100]; // array of pointers
char listOfLines[100][100]; // array of char arrays
Then use strcpy.
Switched:
listOfLines[n] = lineBuffer;
strcpy(listOfLines[n], lineBuffer);
Working:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
FILE *unsortedFile; /* prepare file variable */
char lineBuffer[100]; /* prepare variable for each line */
char listOfLines[100][100]; /* prepare line array variable to be sorted */
int n = 0;
int i;
if (argc == 2) /* if a file has been given */
{
unsortedFile = fopen(argv[1], "r"); /* open it readonly */
if (unsortedFile == NULL) /* if it couldn't open */
{
printf("Couldn't open the file %s\n", argv[1]);
printf("Does it exist?\n");
return -1; /* stop the program here, return non-zero for error */
}
printf("original file:\n\n");
while (fgets(lineBuffer, sizeof(lineBuffer), unsortedFile))
{
printf("%s", lineBuffer);
strcpy(listOfLines[n], lineBuffer); /* store line buffer to the array */
n = n + 1; /* increase n for the next array element */
}
printf("\nLines to be sorted: %d\n", n);
for (i = 0; i < n; i++)
{
printf("%s", listOfLines[i]);
}
} else /* if no or too many args provided */
{
printf("\nArgument error - you either didn't supply a filename\n");
printf("or didn't surround the filename in quotes if it has spaces\n\n");
return -1; /* return non-zero for error */
}
}

Program works with string literals but not with string arrays

I have a hashtable ADT which has two functions, insert and lookup. I put in to the insert function a hash table, hash table size, ID #, and book title and that inserts it into the hash table. This works fine when I pass it a string literal, i.e. insert(...,"Hello, world!"...); It doesn't work when I read in strings from a file, store them in an array, and try and use my insert and lookup functions.
I have all of my code here but the most important files are main.c and hash.c. Hash.c has the newHash(), hash(), insert(), and lookup() functions and main.c reads from two files, in this case test1.lib.in and test1.req.in, and from the first file will get the library id and title of a book from each line and then put it in the hash table. From the second file, it gets requests for a book title and should print the ids in its linked list.
List of links to files https://docs.google.com/document/d/1tFNs-eVkfnCfjwAHcAUdHtUl1KVv_WcnW2IS0SRFvcM/edit?usp=sharing
Example of code that works.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "list.h"
#include "hash.h"
int main(){
ListHndl* temp = newHash(10);
insert(442440, "cvyaqbznxel", 10,temp);
lookup(temp,"cvyaqbznxel", 10);
return 0;
}
Code that doesn't work
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "list.h"
#include "hash.h"
int main(int argc, char * argv[]) {
if (argc != 3) {
printf("Incorrect arguments, please specify 2 files to be read\n");
return EXIT_FAILURE;
}
FILE *file = fopen( argv[1], "r");
FILE *secondFile = fopen(argv[2], "r");
if (file == 0 || secondFile == 0) {
printf("Could not open a file\n");
return EXIT_FAILURE;
}
int numDataLines2;
int numDataLines;
int hashTableSize;
//First line of first file gives number of lines in file and
//size of hash table to be made
if(fscanf(file, "%d%d", &numDataLines, &hashTableSize) < 2) {
printf("Unable to parse first line of first file\n");
return EXIT_FAILURE;
}
ListHndl* theHash = newHash(hashTableSize);
int libraryID;
char *tempString = calloc(numDataLines,41*sizeof(char));
char lineHolder[129];
//discard the new line which always shows up
fgets(lineHolder, 128, file);
for(int i = 0; i < numDataLines; i++) {
//Gets the whole line to be scanned with sscanf
fgets(lineHolder, 128, file);
//If the line consists of just a newline char, continue
if(strcmp(lineHolder, "\n") == 0 ) {
continue;
}
//Scans the line retrieved from fgets and placed in lineHolder
if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID,&tempString[i]) == 0){
printf("Unable to parse line %d of first file\n",i+2);
return EXIT_FAILURE;
}
insert(libraryID, &tempString[i], hashTableSize, theHash);
}
char String[41];
fgets(String, 40, secondFile);
numDataLines2 = atoi(String);
char *storeSecondFileStuff = calloc(numDataLines2,41*sizeof(char));
for(int i = 0; i< numDataLines2; i++) {
fgets(lineHolder, 128, secondFile);
if(strcmp(lineHolder, "\n") == 0) {
continue;
}
if(sscanf(lineHolder, "%40[^\n]",&storeSecondFileStuff[i]) == 0) {
printf("Unable to parse line %d of second file\n",i+2);
return EXIT_FAILURE;
}
lookup(theHash, &storeSecondFileStuff[i], hashTableSize);
}
printf("\n");
fclose(file);
fclose(secondFile);
return 0;
}
Thanks!
I think you have multiple problems. To start with, you might not be scanning your input line correctly. Change your line
if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID,&tempString[i]) == 0)
to
if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID, tempString) < 0)
that way, you will trap the situation where the sscanf function did not successfully convert both arguments - for example, if there is no comma in the input line. Note that sscanf returns the number of successful conversions; success would return a value of 2, so testing for <2 is the right way to go.
Note also that I changed &tempString[i] to tempString. The former points to some place along tempString - which only has 41 characters allocated to it. Yet you always allow up to 40 characters (plus '\0' to be written to it - so you will write past the end of the string. Since this is only a temporary variable, there is no sense in doing this. Just scan the input into the temp variable, then do whatever you need to do with it.
This means that your insert also changes, from
insert(libraryID, &tempString[i], hashTableSize, theHash);
to
insert(libraryID, tempString, hashTableSize, theHash);
Again, you need to do the same thing lower down in your code.
Here is an attempt at making the code work for you - see if this hits the spot. Note that all I really did was change the type of tempString and storeSecondFileStuff, and modified the way they were used in various function calls accordingly. I did not attempt to compile / run because of the complexity of the other files involved - but this should help a bit:
int main(int argc, char * argv[]) {
if (argc != 3) {
printf("Incorrect arguments, please specify 2 files to be read\n");
return EXIT_FAILURE;
}
FILE *file = fopen( argv[1], "r");
FILE *secondFile = fopen(argv[2], "r");
if (file == 0 || secondFile == 0) {
printf("Could not open a file\n");
return EXIT_FAILURE;
}
int numDataLines2;
int numDataLines;
int hashTableSize;
//First line of first file gives number of lines in file and
//size of hash table to be made
if(fscanf(file, "%d%d", &numDataLines, &hashTableSize) < 2) {
printf("Unable to parse first line of first file\n");
return EXIT_FAILURE;
}
ListHndl* theHash = newHash(hashTableSize);
int libraryID;
char **tempString = calloc(numDataLines,sizeof(char*)); // <<< ARRAY of pointers
char lineHolder[129];
//discard the new line which always shows up
fgets(lineHolder, 128, file);
for(int i = 0; i < numDataLines; i++) {
//Gets the whole line to be scanned with sscanf
fgets(lineHolder, 128, file);
tempString[i] = calloc(1, 41 * sizeof(char)); // <<< space for this string
//If the line consists of just a newline char, continue
if(strcmp(lineHolder, "\n") == 0 ) {
continue;
}
//Scans the line retrieved from fgets and placed in lineHolder
if(sscanf(lineHolder, "%d, %40[^\n]", &libraryID, tempString[i]) < 0){ // <<< changed
printf("Unable to parse line %d of first file\n",i+2);
return EXIT_FAILURE;
}
insert(libraryID, tempString[i], hashTableSize, theHash); // <<< changed
}
char String[41];
fgets(String, 40, secondFile);
numDataLines2 = atoi(String);
char **storeSecondFileStuff = calloc(numDataLines2, sizeof(char*)); // changed: again char **
for(int i = 0; i< numDataLines2; i++) {
fgets(lineHolder, 128, secondFile);
storeSecondFileStuff[i] = calloc(1, 41 * sizeof(char));
if(strcmp(lineHolder, "\n") == 0) {
continue;
}
if(sscanf(lineHolder, "%40[^\n]",storeSecondFileStuff[i]) == 0) {
printf("Unable to parse line %d of second file\n",i+2);
return EXIT_FAILURE;
}
lookup(theHash, storeSecondFileStuff[i], hashTableSize); // <<<< changed
}
printf("\n");
fclose(file);
fclose(secondFile);
return 0;
}

Issues accessing a struct array when it is sent into a function

I am a new C programmer and so you will have to excuse my lack of knowledge. Slowly but surely I am improving. I am wondering why I am unable to access the members of my structure after I have sent them to a function that intends to modify them. This issue occurs in the code shown below. Basically my program analyzes an XML document and looks for certain patterns to extract text. In my main function I make the struct: artinfo artIn[128] = {}; which is defined in my header file as being:
#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
After instantiating this and clearing it with memset I proceed to send it to another function which will extract text and intends to put it back in the structure. The function is shown below.
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,">");
}
Everything seems to work just fine until its reaches the: strcpy((*artIn[0]).title, buffer); and printf("The title is: %s\n", ((*artIn[0]).title); statements. I always get an error and a stack dump - i.e. 1 [main]Parst_Text 7296 open_stackdumpfile: Dumping stack trace to Parse_Text.exe.stackdump
I am not really sure what I am doing wrong - I think it is the call to access the member of the struct array as if I remove these statements the program runs without flaw. I am not sure if I am just putting too much on the stack or how to use the stack dump to figure out the problem. All advice is appreciated but please keep it constructive. Thanks. Also please let me know if I overloaded this question as I wasn't sure how much detail to provide.
EDIT: as per request here is the function which calls reader parser
#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;
}
With this function declaration:
bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo *artIn[])
the 4th argument will be an array of pointers to artinfo structures, not a pointer to an array of artinfo structures. When it tries to de-reference these supposed pointers, it fails.
Instead it should be:
bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo (*artIn)[])
In addition, fixing these would at least make your program more robust.
There does not seem to be any check for overflowing buffer
You do not explicitly place a null character at the end of buffer. Although you do memset it before entering your loop, if it did overflow then not only might it be too long, it might also not be null terminated.
You should use strncpy instead of strcpy, otherwise you run the risk of overflowing the space allocated in the destination string. Also as noted by Matt, you should manually add a null character to the end of your string after calling strncpy.
There are already many suggestions on how you can improve the robustness of your code. I'm going to answer to the main problem you mentioned in your original post.
You said,
Everything seems to work just fine until its reaches the: strcpy((*artIn[0]).title, buffer); and printf("The title is: %s\n", ((*artIn[0]).title); statements. I always get an error and a stack dump - i.e. 1 [main]Parst_Text 7296 open_stackdumpfile: Dumping stack trace to Parse_Text.exe.stackdump I am not really sure what I am doing wrong
The culprit for that problem is that you have
bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo *artIn[])
but when you are calling the function, you are using:
readerParser(fp, op, lbuf, artIn);
I am surprised that the compiler didn't flag a warning or an error. artIn is declared as:
artinfo artIn[128] = {};
When you use artIn in a function call, it degrades to a pointer of type artinfo*. It would be good when the argument type of an argument is artinfo* artIn or artinfo artIn[] but not artinfo* artIn[].
You should change the type of artIn in readerParser, both in the declaration and the definition.
bool readerParser(FILE *input, FILE *output, textlbuf *lbuf, artinfo artIn[])
And then replace all usages of *artIn in that function with just artIn.
Hope this helps.

Resources