Assigning data to 2D array and displaying it C - c

I am writing a program, that will open csv file and save data to 3D array.
Most of code works pretty good, but I have a problem with assiging records to 2D array.
Here is a code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FILE_MODE "r"
/*
Explode string with given token and assign result to list variable
*/
int explode(const char *src, const char *tokens, char ***list, size_t *len)
{
if(src == NULL || list == NULL || len == NULL) {
return 0;
}
char *str, *copy, **_list = NULL, **tmp;
*list = NULL;
*len = 0;
copy = strdup(src);
if(copy == NULL)
return 1;
str = strtok(copy, tokens);
if(str == NULL) {
goto free_and_exit;
}
_list = realloc(NULL, sizeof *_list);
if(_list == NULL) {
goto free_and_exit;
}
_list[*len] = strdup(str);
if(_list[*len] == NULL)
goto free_and_exit;
(*len)++;
while((str = strtok(NULL, tokens)))
{
tmp = realloc(_list, (sizeof *_list) * (*len + 1));
if(tmp == NULL)
goto free_and_exit;
_list = tmp;
_list[*len] = strdup(str);
if(_list[*len] == NULL)
goto free_and_exit;
(*len)++;
}
free_and_exit:
*list = _list;
free(copy);
return 2;
}
/*
Exploding lines in CSV file
*/
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ";");
tok && *tok;
tok = strtok(NULL, ";\n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE *stream;
char fileName[256], table[256], line[256],
**list, **columns, **data;
size_t length;
printf("Witaj uzytkowniku! Podaj nazwe pliku z rozszerzeniem .csv. \n");
scanf("%s", fileName);
explode(fileName, ".", &list, &length);
strcpy(table, list[0]);
stream = fopen("file.csv", FILE_MODE); // not to write path every single time
if (stream == NULL) {
printf("Nie moge otworzyc pliku %s do odczytu!\n", fileName);
exit(1);
}
fgets(line, sizeof line, stream);
explode(line, ";", &columns, &length);
int recordNumber = 0
,columnNumber = 0;
while (fgets(line, sizeof line, stream))
{
char* tmp = strdup(line);
if (getfield(tmp, recordNumber) != NULL) {
columnNumber++;
}
recordNumber++;
free(tmp);
}
fseek(stream, 0, SEEK_SET); // Go to beginning of file
fgets(line, 1024, stream);
int i = 0 // Number of records
,h = 0; // number of columns
char **records[recordNumber][columnNumber];
length = 0;
char *tmp[recordNumber];
// Here I get number of lines and columns in csv file to make 3D array??
while (fgets(line, sizeof line, stream) && i < recordNumber)
{
tmp[i] = strdup(line);
explode(tmp[i], ";", &data, &length);
for (h = 0; h < columnNumber; h++)
{
memcpy(records[i][h], data[h], sizeof(data[h]));
}
i++;
}
for (i = 0; i < recordNumber; i++)
{
for (h = 0; h < columnNumber; h++)
{
printf("%s ", records[i][h][0]);
}
printf("\n");
}
fclose(stream);
return EXIT_SUCCESS;
}
Problem starts, when I try do a loop, that assign data to array:
while (fgets(line, sizeof line, stream) && i < recordNumber)
{
tmp[i] = strdup(line);
explode(tmp[i], ";", &data, &length);
for (h = 0; h < columnNumber; h++)
{
memcpy(records[i][h], data[h], sizeof(data[h]));
}
i++;
}
I tried to use memcpy and strcpy, but none works correctly - I am pretty sure.
When code goes to these lines, there is an error: segmentation fault (core dumping).
All i want to achieve is to fill this array with data from csv file and print it.
Thanks for your help! :)
EDIT:
explode function is not mine. Probably, I found it somewhere on stackoverflow.
When, it comes to the code, after little change, it works
char records[recordNumber][columnNumber][1024];
length = 0;
char *tmp[recordNumber];
while (fgets(line, sizeof line, stream) && i < recordNumber)
{
tmp[i] = strdup(line);
explode(tmp[i], ";", &data, &length);
for (h = 0; h < columnNumber; h++)
{
strcpy(records[i][h], data[h]);
}
i++;
}

Read each line of the file with fgets. strpbrk can be used to find the delimiters. Two pointers can be used to get the number of characters between the delimiters. Then allocate memory and use memcpy to copy the field to the allocated memory.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char ***strpdlm ( char *pdelim, int skip);
char ***freedlm ( char ***ppp);
int main()
{
char ***expld = NULL;
int line = 0;
int field = 0;
//last argument of 1 is skip consecutive delimiters. 0 do not skip
expld = strpdlm ( ";\n", 1);// delimiters semicolon and newline
//print each extracted string
line = 0;
if ( expld) {//not null
while ( expld[line]) {//not null
field = 0;
printf ( "\nfields for line %d\n", line);
while ( expld[line][field]) {//not null
printf ( "expld[%d][%d] %s\n", line, field, expld[line][field]);
field++;
}
line++;
}
}
//free memory and set NULL
expld = freedlm ( expld);
return 0;
}
char ***freedlm ( char ***ppp) {
size_t each = 0;
size_t item = 0;
if ( ppp) {
while ( ppp[each]) {
item = 0;
while ( ppp[each][item]) {
free ( ppp[each][item]);
item++;
}
free ( ppp[each]);
each++;
}
free ( ppp);
}
return NULL;
}
char ***strpdlm ( char *pdelim, int skip) {
char ***xpld = NULL;
char ***temprecord = NULL;
char **tempfield = NULL;
char *pnt = NULL;
char *cur = NULL;
char line[1024] = "";
int span = 0;
int len = 0;
int record = 0;
int field = 0;
FILE *pf = NULL;
if ( ( pf = fopen ( "file.csv", "r")) == NULL) {
perror ( "could not open \"file.csv\"");
return NULL;
}
if ( pdelim) {
while ( fgets ( line, sizeof line, pf)) {
//make sure each line ends with \n
len = strcspn ( line, "\n");
if ( len + 1 < sizeof line) {
line[len] = '\n';
line[len + 1] = '\0';
}
//allocate record + 2 pointers
if ( ( temprecord = realloc ( xpld, ( record + 2) * sizeof ( *xpld))) == NULL) {
fprintf ( stderr, "problem realloc records\n");
fclose ( pf);
return xpld;
}
xpld = temprecord;
xpld[record] = NULL;
field = 0;
cur = line;//cur points to line
while ( ( pnt = strpbrk ( cur, pdelim))) {
if ( pnt != cur || !skip) {
if ( ( tempfield = realloc ( xpld[record], ( field + 2) * sizeof ( **xpld))) == NULL) {
fprintf ( stderr, "problem realloc fields\n");
fclose ( pf);
return xpld;
}
xpld[record] = tempfield;
xpld[record][field] = NULL;
if ( pnt) {
span = pnt - cur;
}
else {
span = strlen ( cur);
}
if ( ( xpld[record][field] = malloc ( span + 1)) == NULL) {
fprintf ( stderr, "problem malloc\n");
fclose ( pf);
return xpld;
}
memcpy ( xpld[record][field], cur, span);
xpld[record][field][span] = '\0';
field++;
xpld[record][field] = NULL;//sentinel NULL
}
cur = pnt + 1;//set cur to point to next field
}
record++;
xpld[record] = NULL;//sentinel NULL
}
}
fclose ( pf);
return xpld;
}

Related

Function cannot find failed memory allocation

Function int load(const char *filename, int ***ptr, enum save_format_t format) should load data from binary or text file (which name is saved under filename pointer) to matrix which is under ptr pointer to matrix. File extension depends on value of variable format: 0 or 1 (in function I showed there is only option with format=0, which is primarily for text files, because only this one makes trouble). Proper data in file looks for example as below:
10 20 30 40 50 60 70 -1
100 200 300 400 500 600 700 800 -1
For data exact like an example above, data should be loaded like this:
int A[] = {10, 20, 30, 40, 50, 60, 70, -1};
int B[] = {100, 200, 300, 400, 500, 600, 700, 800, -1};
int D[] = {A, B, C, NULL};
That means that every row has to end with '-1', (data has to be loaded to matrix with '-1'). Pointer to row after the last row should be equal to NULL.
If in any part off function allocation failed, function should return 4.
Tests carried out on file with extension ".bin" and with heap limit return this error:
Function should return 4, but it returned 0.
I use notation like for example **ptr because I'm not allowed to use square brackets.
Can someone help me how can I make my function return the right integer. My function is as it follows:
int load(const char *filename, int ***ptr, enum save_format_t format) {
if (filename == NULL || ptr == NULL || format != 0 && format != 1) {
return 1;
}
int val = 0;
int **temp = NULL;
FILE *fp, *pp;
if (format == 0) {
int i = 0, x = 0, h = 0, w = 0;
fp = fopen(filename, "r");
if (fp == NULL) {
return 2;
}
pp = fopen(filename, "r");
if (pp == NULL) {
fclose(fp);
return 2;
}
int val2 = 0;
while (1) {
if (fscanf(fp, "%d", &val2) != 1) {
if (i == 0 || val != -1) {
fclose(fp);
fclose(pp);
return 3;
}
break;
}
val = val2;
if (val == -1) {
h++;
}
i++;
}
if (i == h) {
fclose(fp);
fclose(pp);
return 3;
}
i = 0;
fseek(fp, 0, SEEK_SET);
temp = malloc(sizeof(temp) * (h + 1));
if (temp == NULL) {
fclose(fp);
fclose(pp);
return 4;
}
*(temp + h) = NULL;
for (i = 0; i < h; i++) {
val = 0, w = 0;
while (val != -1) {
if (fscanf(pp, "%d", &val) == EOF) {
break;
}
w++;
}
if (*(temp + i) != NULL) {
*(temp + i) = (int *)malloc(sizeof(int) * w);
if (*(temp + i) == NULL) {
for (int s = 0; s < i; s++) {
free(*(temp + s));
}
free(temp);
fclose(pp);
fclose(fp);
return 4;
}
} else {
fclose(fp);
fclose(pp);
free(temp);
return 0;
}
for (x = 0; x < w; x++) {
fscanf(fp, "%d", *(temp + i) + x);
}
}
fclose(fp);
fclose(pp);
}
*ptr = temp;
return 0;
}
There are multiple problems in your code:
if (i == h) seems incorrect: what if the file contains a single row with a -1 terminator, in other words an empty matrix?
temp = malloc(sizeof(temp) * (h + 1)); should be temp = malloc(sizeof(*temp) * (h + 1));
if (*(temp + i) != NULL) { read an uninitialized entry in the array allocated by malloc(). The test should be removed and you should always allocate the row.
Here is a modified version:
int load(const char *filename, int ***ptr, enum save_format_t format) {
if (filename == NULL || ptr == NULL || format != 0 && format != 1) {
return 1;
}
int **temp = NULL;
FILE *fp, *pp;
if (format == 0) {
int i = 0, x = 0, h = 0, w = 0, val = 0;
fp = fopen(filename, "r");
if (fp == NULL) {
return 2;
}
pp = fopen(filename, "r");
if (pp == NULL) {
fclose(fp);
return 2;
}
// determine the number of rows
val = 0;
while (fscanf(fp, "%d", &val) == 1) {
if (val == -1)
h++;
}
if (val != -1) {
// empty file or file does not end with -1
fclose(fp);
fclose(pp);
return 3;
}
temp = malloc(sizeof(*temp) * (h + 1));
if (temp == NULL) {
fclose(fp);
fclose(pp);
return 4;
}
fseek(fp, 0, SEEK_SET);
for (i = 0; i < h; i++) {
w = 0;
while (fscanf(pp, "%d", &val) == 1) {
w++;
if (val == -1)
break;
}
if (w == 0 || (*(temp + i) = malloc(sizeof(int) * w)) == NULL) {
while (i-- > 0) {
free(*(temp + i));
}
free(temp);
fclose(pp);
fclose(fp);
return 4;
}
for (x = 0; x < w; x++) {
fscanf(fp, "%d", *(temp + i) + x);
}
}
*(temp + h) = NULL;
fclose(fp);
fclose(pp);
}
*ptr = temp;
return 0;
}
Consider reading a string and parsing with strtol.
The memory allocations will return NULL when there is no RAM available.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <math.h>
int load ( char const *filename, int ***ptr) {
if ( filename == NULL || ptr == NULL) {
return 1;
}
char entry[100] = "";
char *end = NULL;
int **temp = NULL;
int *temprow = NULL;
long int val = 0;
int rows = 0;
int cols = 0;
int problem = 0;
int result = 0;
FILE* fp = NULL;
fp = fopen ( filename, "r");
if ( fp == NULL) {
perror ( filename);
return 2;
}
while ( 1 == ( result = fscanf ( fp, "%99s", entry))) {
if ( -1 == val || ( 0 == rows && 0 == cols)) {
if ( -1 == val) {
++rows;
}
if ( NULL == ( temp = realloc ( *ptr, sizeof **ptr * ( rows + 2)))) {
fprintf ( stderr, "problem realloc *ptr\n");
problem = 4;
break;
}
*ptr = temp;
*( ( *ptr) + rows) = NULL;
*( ( *ptr) + rows + 1) = NULL;//sentinel
cols = 0;
}
errno = 0;
val = strtol ( entry, &end, 10);
if ( entry == end) {//nothing could be parsed to int
problem = 3;
break;
}
else if ( 0 != *end) {//extra characters after int
problem = 3;
break;
}
if ( ( errno == ERANGE && ( val == LONG_MAX || val == LONG_MIN))
|| ( errno != 0 && val == 0)) {// parsing error from strtol
perror ( "input error");
problem = 3;
break;
}
if ( val > INT_MAX || val < INT_MIN) {
problem = 3;
break;
}
if ( NULL == ( temprow = realloc ( *( ( *ptr) + rows), sizeof ***ptr * ( cols + 2)))) {
fprintf ( stderr, "problem realloc *( (*ptr) + row)\n");
problem = 4;
break;
}
*( ( *ptr) + rows) = temprow;
++cols;
*( *( ( *ptr) + rows)) = cols;//save cols in index 0
*( *( ( *ptr) + rows) + cols) = val;
}
fclose(fp);
if ( 0 == result) {
problem = 3;
}
return problem;
}
int main ( void) {
char const *filename = "ints.txt";
int **array = NULL;
int row = 0;
int each = 0;
load ( filename, &array);
row = 0;
while ( array && ( *(array + row))) {
each = 0;
while ( each <= *( *(array + row))) {
printf ( "%d\n", *( *(array + row) + each));
++each;
}
++row;
}
row = 0;
while ( array && ( *(array + row))) {
free ( *(array + row));
++row;
}
free ( array);
return 0;
}

Parse comma serpataed file of different types

This is what I came up with for reading a csv file with multiple types. It seems to get the job done in all cases but 1,2,,"a". Where there is a blank space. Can I please have some ideas on how to fix this?
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",\n"))
{
if (!--num)
return tok;
}
return NULL;
}
while(fgets(line, 80, inputfp1) != NULL)
{
printf(" line is %s \n", line);
char* tmp1 = strdup(line);
char* tmp2 = strdup(line);
char* tmp3 = strdup(line);
char* tmp4 = strdup(line);
printf("Field 1 would be %s\n", getfield(tmp1, 1));
printf("Field 2 would be %s\n", getfield(tmp2, 2));
printf("Field 3 would be %s\n", getfield(tmp3, 3));
printf("Field 4 would be %s\n", getfield(tmp4, 4));
// NOTE strtok clobbers tmp
free(tmp1);
free(tmp2);
free(tmp3);
free(tmp4);
//sscanf(line, "%d, %d, %d, %d", &column1[i], &column2[i], &column3[i], &column4[i]);
//printf(" column1[i] is %d column2[i] is %d column3[i] is %d column4[i] is %d \n", column1[i], column2[i], column3[i], column4[i]);
i++;
memset(line, 0, 80);
}
Ok I used a library like was suggested and don't understand why this is not working.
https://ideone.com/RylYp1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Given a string which might contain unescaped newlines, split it up into
* lines which do not contain unescaped newlines, returned as a
* NULL-terminated array of malloc'd strings.
*/
char **split_on_unescaped_newlines(const char *txt) {
const char *ptr, *lineStart;
char **buf, **bptr;
int fQuote, nLines;
/* First pass: count how many lines we will need */
for ( nLines = 1, ptr = txt, fQuote = 0; *ptr; ptr++ ) {
if ( fQuote ) {
if ( *ptr == '\"' ) {
if ( ptr[1] == '\"' ) {
ptr++;
continue;
}
fQuote = 0;
}
} else if ( *ptr == '\"' ) {
fQuote = 1;
} else if ( *ptr == '\n' ) {
nLines++;
}
}
buf = malloc( sizeof(char*) * (nLines+1) );
if ( !buf ) {
return NULL;
}
/* Second pass: populate results */
lineStart = txt;
for ( bptr = buf, ptr = txt, fQuote = 0; ; ptr++ ) {
if ( fQuote ) {
if ( *ptr == '\"' ) {
if ( ptr[1] == '\"' ) {
ptr++;
continue;
}
fQuote = 0;
continue;
} else if ( *ptr ) {
continue;
}
}
if ( *ptr == '\"' ) {
fQuote = 1;
} else if ( *ptr == '\n' || !*ptr ) {
size_t len = ptr - lineStart;
if ( len == 0 ) {
*bptr = NULL;
return buf;
}
*bptr = malloc( len + 1 );
if ( !*bptr ) {
for ( bptr--; bptr >= buf; bptr-- ) {
free( *bptr );
}
free( buf );
return NULL;
}
memcpy( *bptr, lineStart, len );
(*bptr)[len] = '\0';
if ( *ptr ) {
lineStart = ptr + 1;
bptr++;
} else {
bptr[1] = NULL;
return buf;
}
}
}
}
int main(void) {
// your code goes here
char line[80] = "52,243,,542";
split_on_unescaped_newlines(line);
printf("line %s\n", line[0]);
printf("line %s\n", line[1]);
return 0;
}

realloc : corrupted data returned

I'm trying to read from a file using C and after shrinking the size using realloc I get corrupted data. I don't really see what the problem could be.
Here's the function that returns the string :
char *read_string(FILE *fichier) {
char car = 0;
size_t size = 1;
char *symbole = realloc(NULL, sizeof(char) * size);
char *s;
size_t len = 0;
if (!symbole)
return symbole;
else
s = symbole;
do {
car = getc(fichier);
} while (car != '"' && car != EOF);
if (car == EOF)
return EOFP;
else {
car = getc(fichier);
while (car != '"' ) {
s[len] = car;
car = getc(fichier);
len++;
if (len == size) {
symbole = realloc(s, sizeof(char) * (size += 1));
if (!symbole)
return symbole;
else
s = symbole;
}
}
s[len] = '\0' ;
symbole = realloc(s, sizeof(char) * len);
if (!symbole) {
printf("WTF");
return symbole;
} else
s = symbole;
return s;
}
}
My main function is:
int main(int argc, char *argv[]) {
FILE *fichier = NULL;
fichier = fopen("C:/Users/Nabila K/Documents/test.json", "r");
if ((fichier != NULL)) {
while (feof(fichier) == 0) {
char *test = read_string(fichier);
if (test == NULL) {
printf("test == NULL\n");
exit(1);
} else
if (test == EOFP) {
} else {
printf("%s\n", test);
free(test);
}
}
fclose(fichier);
} else {
exit(EXIT_FAILURE);
}
return 0;
}
UPDATE
My json file looks something like this :
{
"KARIM BENNI" : {
"2017-08-07 09:50:50" : {
"Anomalie" : {
"description" : "Test",
"theme" : "Engins mobiles"
},
"date" : "2017-08-07",
"date_now" : "2017-08-07 09:50:50",
"entite" : "USINE LAMINAGE A FROID",
"etat" : "Cree",
"nb_personne" : 2,
"temps" : 5,
"visiteur" : "KARIM BENNI",
"visite" : "AHMED RABII",
"zone" : "COUPE"
}
}
}
There are multiple issues in your code:
char car = 0; is incorrect: you must define car as int to correctly distinguish all values returned by getc(), especially EOF.
while (feof(fichier) == 0) is always wrong. Learn why there: Why is “while ( !feof (file) )” always wrong?
EOFP is not defined, you should probably use NULL instead for more clarity.
the final realloc() to shrink the allocated block is one byte too short. You must keep len+1 bytes for len characters plus the null terminator.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
char EOFP[1]; /* special value used to signal end of file */
char *read_string(FILE *file) {
int c;
size_t size, len;
char *symbol;
char *s;
while ((c = getc(file)) != '"') {
if (c == EOF)
return EOFP;
}
size = 16;
len = 0;
symbol = malloc(size);
if (symbol == NULL) {
/* allocation failure */
return NULL;
}
while ((c = getc(file)) != '"') {
if (c == EOF) {
/* premature end of file in the middle of a string */
free(symbol);
return EOFP;
}
if (len + 2 < size) {
size += size;
s = realloc(symbol, size);
if (s == NULL) {
/* allocation failure */
free(symbol);
return NULL;
}
symbol = s;
}
symbol[len++] = c;
}
symbol[len] = '\0';
s = realloc(symbol, len + 1);
return s ? s : symbol;
}
int main(int argc, char *argv[]) {
FILE *file = fopen("C:/Users/Nabila K/Documents/test.json", "r");
if (file != NULL)) {
char *test;
while ((test = read_string(file)) != EOFP) {
if (test == NULL) {
printf("test == NULL\n");
exit(1);
} else {
printf("%s\n", test);
free(test);
}
}
fclose(file);
} else {
exit(EXIT_FAILURE);
}
return 0;
}
Notes:
Parsing the full JSON syntax for strings would be required if the strings can contain escaped characters such as \" or \n, \\ etc.

fscanf() replacing my ADT nodes?

I am writing a function to read from a text file and extract the strings word by word and store them to a binary search tree. The function should ignore all punctuations and discard duplicate words(only adds to the word frequency).
My problem with the code now is that every time "while (fscanf(fp, "%s", line)!=EOF)" runs, my rootWord gets replaced by the newly read word. I cannot figure out how is it possible for fscanf to be able to do this.
typedef struct word * wordPtr;
typedef struct position * positionPtr;
typedef struct position
{
int position;
positionPtr nextPosition;
} Position;
typedef struct word
{
char * word;
unsigned freq;
positionPtr firstPosition;
wordPtr leftWord;
wordPtr rightWord;
} Word;
typedef struct bstWord
{
wordPtr rootWord;
unsigned wordCount;
} BSTWord;
int BSTCreate(BSTWord* bst, char* fileName)
{
FILE * fp = fopen(fileName,"r");
char line[MAX_WORD_LEN + 1];
int charCount = 0;
char * token;
char delimit[] = "\t\r\n\v\f,.-;:\"\' ";
while (fscanf(fp, "%s", line)!=EOF)
{
wordPtr prev = NULL, curr = bst->rootWord;
wordPtr newWord;
positionPtr newPosition;
int lessThen;
int status = 1;
token = strtok(line, delimit);
charCount = charCount + 1;
while(curr!=NULL)
{
prev = curr;
if(strcmp(token, curr->word)<0)
{
printf("\nless");
lessThen = 1;
curr = curr->leftWord;
status = 1;
}
else if(strcmp(token, curr->word)>0)
{
printf("\nmore");
lessThen = 0;
curr = curr->rightWord;
status = 1;
}
else if(strcmp(token, curr->word)==0) //If word is already in tree, add freq + update position
{
if ( ( newPosition = malloc( sizeof( Position ) ) ) == NULL )
return FAILURE;
newPosition->position = charCount;
newPosition->nextPosition = NULL;
positionPtr prevPosition = NULL, currPosition = curr->firstPosition;
while(currPosition!=NULL)
{
prevPosition = currPosition;
currPosition = currPosition->nextPosition;
}
prevPosition->nextPosition = newPosition;
status = 0;
curr = NULL;
break;
}
}
if(status == 1)
{
if ( ( newWord = malloc( sizeof( Word ) ) ) == NULL )
return FAILURE;
if ( ( newPosition = malloc( sizeof( Position ) ) ) == NULL )
return FAILURE;
newPosition->position = charCount;
newWord->word = token;
newWord->freq = 1;
newWord->firstPosition = newPosition;
newWord->leftWord = NULL;
newWord->rightWord = NULL;
if(bst->rootWord == NULL)
bst->rootWord = newWord;
else
{
if(lessThen)
{
prev->leftWord = newWord;
}
else
{
prev->rightWord = newWord;
}
}
}
bst->wordCount++;
}
fclose(fp);
free(fp);
return SUCCESS;
}
newWord->word = token;
Every token points to the same memory you allocated at:
char line[MAX_WORD_LEN + 1];
You need to allocate additional memory and copy the string there:
newword->word = malloc(strlen(token) + 1);
strcpy(newword->word, token);

How to implement `.nf` formatting feature

I have written a program that reads a text file inputted by the user, and inside the file contains formatting features such as .br , .sp and .nf.
.nf symbolises no fill, also meaning that when you see any formatting feature after .nf they should all be ignored and it should just output the text in the format it originally appears in the text file.
For example:
.nf Hello my name is .br Jay.
Output:
Hello my name is Jay
If .nf was not there the output would be:
Hello my name is
Jay.
Here's my code:
int main(void) {
FILE *fp = NULL;
char file_name[257] = {'\0'};
char line[61] = {'\0'};
char word[61] = {'\0'};
int out = 0;
int blanks;
int space;
int useFormats = 1;
printf ( "Enter file name:\n");
scanf ( " %256[^\n]", file_name);
if ( ( fp = fopen ( file_name, "r")) == NULL) {
printf ( "could not open file\n");
return 1;
}
while (useFormats == 1){
while ( ( fscanf ( fp, "%60s", word)) == 1) { //breaks the sentence after .br
if ( strcmp ( word, ".br") == 0) {
printf ( "%s\n", line);
line[0] = '\0';
out = 1;
}
if ( strcmp ( word, ".nf") == 0) {// stop filling lines (no fill)
useFormats == 0;
line[0] = '\0';
out = 1;
}
if ( strncmp ( word, ".sp", 3) == 0) { // creates n amount of spaces after .sp
if ( ( sscanf ( &word[3], "%d", &blanks)) == 1) {
printf ( "%s\n", line);
while ( blanks) {
blanks--;
printf ( "\n");
}
line[0] = '\0';
out = 1;
}
else {
printf ( "%s\n", line);
line[0] = '\0';
out = 1;
}
}
else if ( strlen ( line) + strlen ( word) + 1 < 60) {
strcat ( line, " ");
strcat ( line, word);
out = 0;
}
else {
printf ( "%s\n", line);
strcpy ( line, word);
out = 1;
}
}
if ( !out) {
printf ( "%s\n", line);
}
fclose ( fp);
return 0;
}
}
I tried creating a variable called useFormats which is true whilst running and I make it false when it reaches to the .nf feature but nothing happens. I'm not sure if I should remove the if statement and create another while loop to say while (useFormats == 0) to implement the .nf feature.
This should capture the ".nf" token and set useFormats to zero. Adding if ( useFormats == 1) { to the other format conditions should disable them.
#include <stdio.h>
#include <string.h>
#define WIDTH 80
int main(void) {
FILE *fp = NULL;
char file_name[257] = {'\0'};
char line[61] = {'\0'};
char word[61] = {'\0'};
int out = 0;
int blanks = 0;
int center = 0;
int useFormats = 1;
int margin = 0;
printf ( "Enter file name:\n");
scanf ( " %256[^\n]", file_name);
if ( ( fp = fopen ( file_name, "r")) == NULL) {
printf ( "could not open file\n");
return 1;
}
while ( ( fscanf ( fp, "%60s", word)) == 1) {// read file to end one word at a time
if ( strcmp ( word, ".nf") == 0) {// no formatting)
useFormats = 0;
center = 0;
continue;
}
if ( strncmp ( word, ".ce", 3) == 0) {
if ( useFormats == 1) {
if ( ( sscanf ( &word[3], "%d", &center)) != 1) {
center = 0;
}
}
continue;
}
if ( strncmp ( word, ".sp", 3) == 0) {
if ( useFormats == 1) {
if ( ( sscanf ( &word[3], "%d", &blanks)) == 1) {
margin = 0;
if ( center) {
margin = WIDTH - ( ( WIDTH - strlen ( line)) / 2);
center--;
}
printf ( "%*s\n", margin, line);
while ( blanks) {
blanks--;
printf ( "\n");
}
line[0] = '\0';
out = 1;
}
else {
margin = 0;
if ( center) {
margin = WIDTH - ( ( WIDTH - strlen ( line)) / 2);
center--;
}
printf ( "%*s\n", margin, line);
line[0] = '\0';
out = 1;
}
}
continue;
}
if ( strcmp ( word, ".br") == 0) {
if ( useFormats == 1) {
margin = 0;
if ( center) {
margin = WIDTH - ( ( WIDTH - strlen ( line)) / 2);
center--;
}
printf ( "%*s\n", margin, line);
line[0] = '\0';
out = 1;
}
continue;
}
if ( strlen ( line) + strlen ( word) + 1 <= 60) {
strcat ( line, " ");
strcat ( line, word);
out = 0;
}
else {
margin = 0;
if ( center) {
margin = WIDTH - ( ( WIDTH - strlen ( line)) / 2);
center--;
}
printf ( "%*s\n", margin, line);
strcpy ( line, word);
out = 1;
}
}
if ( !out) {
margin = 0;
if ( center) {
margin = ( WIDTH - strlen ( line)) / 2;
center--;
}
printf ( "%*s\n", margin, line);
}
fclose ( fp);
return 0;
}
As long as this: while ( ( fscanf ( fp, "%60s", word)) == 1) evaluates as true it will never break from the while current inner while loop. You can break out of the inner while loop with break; after your condition is met. It will then check the condition and break out of the main while loop. You also don't assign a value with ==. That operand is for evaluation.
if ( strcmp ( word, ".nf") == 0) {// stop filling lines (no fill)
useFormats = 0;
line[0] = '\0';
out = 1;
break;
}

Resources