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

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.

Related

Segmentation fault due to string copy

In the code below the code crashes after executing while loop for 4th time, and it crashes in strcpy
strcpy(userver_info[location].Tag_Name, field);
When debugging it gave following error
Can't find a source file at "strcpy-sse2-unaligned.S"
I am not able to figureout what is the issue which is causing crash here, after facing the above issue i did structure padding thinking that may be the issue and even that is not working out, can anyone please tell me why is the code crashing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 1024
#define NUM_OF_UNDERLYING_SERVER 0
#define SHM_ADDR_LEN 15
#define SERVER_NAME_LEN 25
#define TAG_NAME_LEN 25
#define TAG_DESC_LEN 30
#define ACCESS_LEVEL_LEN 5
#define DATA_TYPE_NAME_LEN 10
typedef struct {
char SHM_Location[SHM_ADDR_LEN];
char Server_ID[SERVER_NAME_LEN];
char Tag_Name[TAG_NAME_LEN];
int Tag_ID;
char Tag_Description[TAG_DESC_LEN];
char Access_Level[ACCESS_LEVEL_LEN];
char Data_Type[DATA_TYPE_NAME_LEN];
}u_server_info;
typedef struct {
int num_of_tags;
u_server_info *underlying_server_data;
}opcua_u_server;
void parse_underlying_opcua_server(char * buffer, u_server_info *userver_info) {
static int location = 0;
char *field;
/* get SHM_Location */
field = strtok(buffer,",");
strcpy(userver_info[location].SHM_Location, field);
/* get Server_ID */
field=strtok(NULL,",");
strcpy(userver_info[location].Server_ID, field);
/* get Tag_Name */
field = strtok(NULL,",");
strcpy(userver_info[location].Tag_Name, field);
/* get Tag_ID */
field=strtok(NULL,",");
userver_info[location].Tag_ID = atoi(field);
/* get Tag_Description */
field = strtok(NULL,",");
strcpy(userver_info[location].Tag_Description, field);
/* get Access_Level */
field = strtok(NULL,",");
strcpy(userver_info[location].Access_Level, field);
/* get Data_Type */
field = strtok(NULL,",");
strcpy(userver_info[location].Data_Type, field);
/* display the result */
printf("%s\t %s\t %s\t %d\t %s\t %s\t %s\n",
userver_info[location].SHM_Location,
userver_info[location].Server_ID,
userver_info[location].Tag_Name,
userver_info[location].Tag_ID,
userver_info[location].Tag_Description,
userver_info[location].Access_Level,
userver_info[location].Data_Type);
location++;
}
int get_line_count(char *filename) {
FILE *fp;
int line_count = 0;
char c;
fp = fopen(filename, "r");
if (fp == NULL){
printf("Unable to open file '%s' to count lines\n",filename);
return -1;
}
for (c = getc(fp); c != EOF; c = getc(fp))
if (c == '\n') // Increment count if this character is newline
line_count = line_count + 1;
fclose(fp);
return line_count;
}
int main(int argc, char **argv)
{
char filename[] = "underlying_server.csv";
char buffer[BUFFER_SIZE];
FILE *fp;
int tags_count = 0;
opcua_u_server *ua_server = NULL;
/* open the CSV file */
fp = fopen(filename,"r");
if( fp == NULL) {
printf("Unable to open file '%s'\n",filename);
exit(EXIT_FAILURE);
}
tags_count = get_line_count(filename);
/* Allocate memmory for each Underlying server */
ua_server= malloc(sizeof(opcua_u_server));
if (ua_server == NULL) {
printf("Malloc failed");
exit(EXIT_FAILURE);
}
/* Allocate memory for each underlying server tag information */
ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data =
malloc(tags_count * sizeof(ua_server->underlying_server_data));
if (ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data == NULL) {
printf("Malloc failed");
exit(EXIT_FAILURE);
}
/* process the data */
while(fgets(buffer,BUFFER_SIZE,fp)) {
parse_underlying_opcua_server(buffer,
ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data);
}
ua_server->num_of_tags = tags_count;
/*Reset the value for next server*/
tags_count = 0;
/* close file */
fclose(fp);
return(0);
}
My underlying_server.csv is like this
1000,Server_1,Tag_1,3000,Created_tag_3000,AR,BOOL
1001,Server_1,Tag_2,3001,Created_tag_3001,AR,BOOL
1002,Server_1,Tag_3,3002,Created_tag_3002,AR,BOOL
1003,Server_1,Tag_4,3003,Created_tag_3003,AR,BOOL
1004,Server_1,Tag_5,3004,Created_tag_3004,AR,REAL
1005,Server_1,Tag_6,3005,Created_tag_3005,AR,REAL
1006,Server_1,Tag_7,3006,Created_tag_3006,AW,REAL
1007,Server_1,Tag_8,3007,Created_tag_3007,AW,REAL
1008,Server_1,Tag_9,3008,Created_tag_3008,AW,REAL
1009,Server_1,Tag_10,3009,Created_tag_3009,AW,REAL
1010,Server_1,Tag_11,3010,Created_tag_3010,AW,REAL
1011,Server_1,Tag_12,3011,Created_tag_3011,AW,DWORD
1012,Server_1,Tag_13,3012,Created_tag_3012,AW,DWORD
1013,Server_1,Tag_14,3013,Created_tag_3013,AR,DWORD
1014,Server_1,Tag_15,3014,Created_tag_3014,AR,DWORD
1015,Server_1,Tag_16,3015,Created_tag_3015,AR,DWORD
1016,Server_1,Tag_17,3016,Created_tag_3016,AR,DWORD
1017,Server_1,Tag_18,3017,Created_tag_3017,AR,DWORD
1018,Server_1,Tag_19,3018,Created_tag_3018,AR,DWORD
1019,Server_1,Tag_20,3019,Created_tag_3019,AR,DWORD
1020,Server_1,Tag_21,3020,Created_tag_3020,AR,DWORD
1021,Server_1,Tag_22,3021,Created_tag_3021,AW,BOOL
1022,Server_1,Tag_23,3022,Created_tag_3022,AW,BOOL
1023,Server_1,Tag_24,3023,Created_tag_3023,AW,BOOL
1024,Server_1,Tag_25,3024,Created_tag_3024,AW,BOOL
1025,Server_1,Tag_26,3025,Created_tag_3025,AW,BOOL
1026,Server_1,Tag_27,3026,Created_tag_3026,AW,DWORD
1027,Server_1,Tag_28,3027,Created_tag_3027,AR,DWORD
1028,Server_1,Tag_29,3028,Created_tag_3028,AR,DWORD
1029,Server_1,Tag_30,3029,Created_tag_3029,AR,DWORD
1030,Server_1,Tag_31,3030,Created_tag_3030,AR,REAL
I'm sure there is a dup for this, you are allocating the second buffer based on the sizeof the pointer, not the object being pointed to:
/* Allocate memory for each underlying server tag information */
ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data =
malloc(tags_count * sizeof(ua_server->underlying_server_data));
becomes:
/* Allocate memory for each underlying server tag information */
ua_server[NUM_OF_UNDERLYING_SERVER].underlying_server_data =
malloc(tags_count * sizeof(*(ua_server->underlying_server_data)));
Note the actual code *(ua_server->underlying_server_data is bad at this moment, but sizeof is compile-time and is just using the code as a template to get the object size.
I sometimes wish there was a compiler warning for "You asked for the sizeof a pointer"
Never use strcpy, it's insecure, because it doesn't perform any form of bounds constraining and will just soldier on copying until it hits a 0 byte in the source buffer. If the source buffer isn't (properly) 0-terminated, or the contents of the source buffer are too long to fit into the destination, it will create undefined behavior (crash or be vulnerable to attack).
Putting aside the problem with fixed size fields, it is absolutely necessary to check the size limits of buffer operations. The standard function you'd use (although it still isn't perfect) is strncpy (note the extra n). The caveat is, that strncpy will omit the terminating 0 byte if it doesn't fit into the destination.
Since your fields are fixed size you can use it like this
strncpy(userver_info[location].SHM_Location, field, SHM_ADDR_LEN-1);
userver_info[location].SHM_Location[SHM_ADDR_LEN-1] = 0;
i.e. it copies up to SHM_ADDR_LEN-1 bytes and will always put a terminating 0 at the very end of the buffer.

Assign global struct variable outside main And Inside main

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.

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 */
}
}

Check if all char values are present in string

I'm currently working on this assignment and I'm stuck. The objective is to read a file and find if these char values exist in the String from the file. I have to compare a String from a file to another String I put in as an argument. However, just as long as each char value is in the String from the file then it "matches".
Example (input and output):
./a.out file1 done
done is in bonehead
done is not in doggie
Example (file1):
bonehead
doggie
As you can see the order in which is compares Strings does not matter and the file also follows one word per line. I've put together a program that finds if the char value is present in the other String but that is only part of the problem. Any idea how to go about this?
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv){
FILE *f = fopen(argv[1], "r");
char *line = NULL;
size_t len = 0;
ssize_t read;
char *word = argv[2];
if(argc != 3){
printf("./a.out <file> <word>\n");
exit(EXIT_SUCCESS);
}
if(f == NULL){
printf("file empty\n");
exit(EXIT_SUCCESS);
}
// confused what this loop does too
while((read = getline(&line, &len, f)) != -1){
char *c = line;
while(*c){
if(strchr(word, *c))
printf("can't spell \"%s\" without \"%s\"!\n", line, word);
else
printf("no \"%s\" in \"%s\".\n", word, line);
c++;
}
}
fclose(f);
exit(EXIT_SUCCESS);
}
Another approach would simply keep a sum of each character matched in the line read from the file, adding one for each unique character in the word supplied to test, and if the sum is equal to the length of the string made up by the unique characters is the search term, then each of the unique characters in the search term are included in the line read from the file.
#include <stdio.h>
#include <string.h>
#define MAXC 256
int main (int argc, char **argv) {
if (argc < 3 ) { /* validate required arguments */
fprintf (stderr, "error: insufficient input, usage: %s file string\n",
argv[0]);
return 1;
}
FILE *fp = fopen (argv[1], "r");
char line[MAXC] = "";
char *s = argv[2]; /* string holding search string */
size_t slen = strlen(s), sum = 0, ulen;
char uniq[slen+1]; /* unique characters in s */
if (!fp) { /* validate file open */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
memset (uniq, 0, slen+1); /* zero the VLA */
/* fill uniq with unique characters from s */
for (; *s; s++) if (!strchr (uniq, *s)) uniq[sum++] = *s;
ulen = strlen (uniq);
s = argv[2]; /* reset s */
while (fgets (line, MAXC, fp)) { /* for each line in file */
if (strlen (line) - 1 < ulen) { /* short line, continue */
printf ("%s is not in %s", s, line);
continue;
}
char *up = uniq; /* ptr to uniq */
sum = 0; /* reset sum */
while (*up) if (strchr (line, *up++)) sum++; /* count chars */
if (sum < ulen) /* validate sum */
printf ("%s is not in %s", s, line);
else
printf ("%s is in %s", s, line);
}
fclose (fp); /* close file */
return 0;
}
Example Use/Output
$ ./bin/strallcinc dat/words.txt done
done is in bonehead
done is not in doggie
which would work equally well for duplicate characters in the search string. e.g.
$ ./bin/strallcinc dat/words.txt doneddd
doneddd is in bonehead
doneddd is not in doggie
You can decide if you would handle duplicate characters differently, but you should make some determination on how that contingency will be addressed.
Let me know if you have any questions.
confused what this loop does
The while (read ... line obviously reads in lines from your file, placing them in the line variable
*c is a pointer to the start of the variable line and this pointer is incremented by c++, so that each letter in the word from the file is accessed. The while loop will be terminated when *c points to the null terminator (0).
The if (strchr(word ... line is testing if the test word contains one of the letters from the word in the file.
This seems to be the reverse of what you are trying to do - finding if all the letters in the test word can be found in the word from the file.
The printf lines are not sensible because there is no either/or - you need one line to print 'yes' our letters are present and one line to print 'no' at least one letter is not present.
The printf statements should be outside the comparison loop, so that you don't get multiple lines of output for each word. Add a flag to show if any letter does not exist in the word. Set flag to 1 at start, and only change it to 0 when a letter is not present, then use the flag to print one of the two outcome statements.
This code snippet may help
/* set flag to 'letters all present' */
int flag = 1;
/* set pointer c to start of input line */
c = word;
/* test word from file for each letter in test word */
while(*c) {
if(strchr(line, *c) == NULL) {
/* set flag to letter not present */
flag = 0;
break;
}
c++;
}

Debug Assertion Error in C

got some code here that won't compile correctly because it is saying that my pointer is already null when i am testing for a not null expression in my main function. here is the code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCODE 53
#define MAXMESSAGE 256
void getCode(char *codeIn, char *filename) {
FILE *codeFile;
/* Open the file with the code */
codeFile = fopen(filename, "r");
if (codeFile == NULL) {
printf("Error opening the code file - program terminated\n");
exit(1);
}
/* Read the first (and assumed only) line from the file */
fgets(codeIn, MAXCODE, codeFile);
/* Terminate the string with /0 */
codeIn[MAXCODE] = '\0';
/* Close the file */
fclose(codeFile);
return;
}
int getMessage(int *message, char *filename) {
FILE *messageFile;
int counter = 0;
/* Open the file with the message */
messageFile = fopen(filename, "r");
if (messageFile == NULL) {
printf("Error opening the message file - program terminated\n");
exit(1);
}
/* Read one number at a time from the file and store it */
while (!feof (messageFile))
{
fscanf (messageFile, "%d", (message+counter));
counter++;
}
/* Close the file */
fclose(messageFile);
return (counter);
}
void sortMessage(int *message, int size) {
int i, j, temp;
for (i=0; i<size-1; i++) {
for (j=i; j<size; j++) {
if (message[i]>message[j]) {
temp = message[i];
message[i] = message[j];
message[j] = temp;
}
}
}
return;
}
void decodeMessage(char *codeIn, int *message, int size) {
FILE *outputFile;
int i = 0;
/* Open the output file */
outputFile = fopen("csis.txt", "w");
if (outputFile == NULL) {
printf("Error opening the output file - program terminated\n");
exit(1);
}
for (i=0; i< size; i++) {
fprintf(outputFile, "%c", codeIn[message[i]%100]);
printf("%c", codeIn[message[i]%100]);
}
printf("\n");
/* Close the file */
fclose(outputFile);
return;
}
int main(int argc, char *argv[])
{
char code[MAXCODE];
int msg[MAXMESSAGE];
int msgSize;
if (argc != 3) {
printf("This program takes two arguments: the name of the file with the code, and the name of the file with the encoded message\n");
}
getCode(code, argv[1]);
msgSize = getMessage(msg, argv[2]);
sortMessage(msg, msgSize);
decodeMessage(code, msg, msgSize);
return;
}
So basically my code is using two files called codefile.txt and msgfile.txt to decode the secret message and write the decoded sequence to a new text file called csis.
As woolstar pointed out in the comments, you don't need to NUL terminate your codeIn array following fgets, because fgets will do that for you. In fact, this constitutes an overflow which we can best see by considering what happens when MAXCODE is 1: codeIn contains only one element: codeIn[0], and accessing codeIn[1] is an error.
Similarly, since MAXCODE is 53 and that's how many elements pointed to by codeIn, codeIn[message[i]%100] is suspicious because there's a potential for message[i]%100 to be an invalid index. While we're on this note, it might be wise to make message[i] an unsigned int so that it can't be negative. The format specifier (for printf and scanf) corresponding to unsigned int is %u.
while ( !feof(messageFile) ) is wrong because the EOF flag isn't set until an attempt is made at reading. Between attempting to read and your EOF test, however, you've incremented counter which means you've counted one too many items. Perhaps your loop should look like this:
while (fscanf(messageFile, "%d", (message+counter)) == 1)
{
counter++;
}
Note that this code assumes you've chosen to keep message[i] as an int. If you've chosen to use unsigned int instead, of course you'll want to use the %u format specifier.
You can probably see that feof is mostly superfluous... You can usually test for erroneous reads by checking the return value. Try to avoid feof in the future.
Your main function has a return type of int, yet at the end of it you have a return; statement which doesn't return an int value. Remove that. It's probably causing errors during compilation.
Presumably, when argv != 3 you want to return from main so you don't end up processing invalid arguments... Make sure you return an int value, e.g.
if (argc != 3) {
printf("This program takes two arguments: the name of the file with the code, and the name of the file with the encoded message\n");
return 0;
}

Resources