How do i ignore newline in .txt file in c - c

i am reading in from a text file and storing each element into a linked list. however when the program reaches a return char or newline the program returns an error.
reading from text file and storing into structs. I notice the error when i print each struct to the screen the program prints the last struct before the return char then quits.
int main(int argc, const char * argv[]) {
printf("Hello!\n");
char filename[] = "artist.txt";
print_artists(read_artists(filename));
return 0;
}
struct artist *read_artists(char *fname)
{
int maxlen = 225;
int artid = 0;
int altartid = 0;
int pc = 0;
char artname[80];
char data[maxlen];
int valid = 0; // 0 acts as true 1 acts as false
int checkresult = 0; //checks result of sscanf
struct artist *temphead = create_artist(0,0,0,"0");
FILE *fp = fopen(fname ,"r");
if (fp != NULL)
{
while (fgets(data,maxlen,fp))
{
checkresult = sscanf(data,"%d\t%[^\t\n]\n",&artid,artname);
if (checkresult == 2)
{
struct artist *b = NULL;
b = create_artist(artid,altartid,pc,artname);
temphead = add_artist(temphead,b);
}
else
{
printf("error checkresult = %d\n",checkresult);
printf("break out of loop valid = 1\n");
valid = 1; // acts as boolean variable
break; //breaks out of the while(fgets)
}
}
fclose(fp);
return (temphead);
}
else
{
fclose(fp);
printf("File Error\n");
return (NULL);
}
}
void print_artists(struct artist *head)
{
if (head != NULL)
{
struct artist *temp = head;
while (temp -> next != NULL)
{
print_artist(temp);
temp = temp -> next;
}
print_artist(temp);
}
}
this is the output
the text file i am reading from

When you reach the blank line before Bodenstandig, the sscanf will not match and you will exit the while loop at the "break".
If sscanf does not return 2, you should check to see if the line is empty and if so skip and read the next line. Or just skip the check and ignore bad lines. The while(fgets(...) condition will become false at the end of the file, so you don't need to exit on a bad line.
if (checkresult == 2)
{
....
}
else
{
continue; // will go back to top while(fgets(...))
}

Related

C program for steganography

Relatively new to programming, been assigned to a task to create a C program to encode and decode 2 ppm images to receive a secret message. I've came up with code but its not getting past the image format if statement in the getPPM function. Any tips on what changes I could make to my code? Also in my main(), am I passing in the correct parameters?
typedef struct NODE {
char *val;
struct NODE *next;
} NODE;
/*
Stores the RGB values of a pixel
*/
typedef struct Pixel {
int red;
int green;
int blue;
} Pixel;
/*
Stores the contents of a PPM file
*/
typedef struct PPM {
char *format;
NODE *comments;
int width, height;
int max;
Pixel *arr;
} PPM;
NODE *copy(NODE *first)
{
NODE *second = NULL, *previous = NULL;
while (first != NULL) {
NODE *temp = (NODE *)malloc(sizeof(NODE));
temp->val = first->val;
temp->next = NULL;
if (second == NULL) {
second = temp;
previous = temp;
} else {
previous->next = temp;
previous = temp;
}
first = first->next;
}
return second;
}
//Copy the PPM File Returning Pointer
struct PPM* createPPM(PPM *old)
{
PPM* new = (PPM *)malloc(sizeof(PPM));
strcpy(new->format, old->format);
new->comments = copy(old->comments);
new->height = old->height;
new->width = old->width;
new->max = old->max;
new->arr = (Pixel *)malloc(old->height * old->width * sizeof(Pixel));
memcpy(new->arr, old->arr, old->height * old->width * sizeof(Pixel));
return new;
}
/*
Returns the PPM struct from the file fd
*/
PPM *getPPM(FILE *fd) {
PPM *image = (PPM *)malloc(sizeof(PPM));
image->format = (char *)malloc(MAX_LEN);
fgets(fd, MAX_LEN, image->format);
sscanf(fd, "%s", image->format);
if (strcmp(image->format, "P3") != 0) {
printf("Invalid Image Type");
exit(0);
}
char c = getc(fd);
image->comments = (NODE*)malloc(sizeof(NODE));
NODE *temp = image->comments;
while ((c = getc(fd)) == '#') {
fseek(fd, -1, SEEK_CUR);
char str[50];
fgets(str, 50, fd);
temp->val = (char*)malloc(strnlen(str, 50));
strcpy(temp->val, str);
temp->val[strlen(temp->val) - 1] = 0;
temp->next = (NODE*)malloc(sizeof(NODE));
temp = temp->next;
temp->next = NULL;
}
fseek(fd, -1, SEEK_CUR);
fscanf(fd, "%d", &image->width);
fscanf(fd, "%d", &image->height);
fscanf(fd, "%d", &image->max);
image->arr = (Pixel*)malloc(image->height * image->width * sizeof(Pixel));
int t = 0;
int j = 0;
while (j < image->height * image->width) {
t = fscanf(fd, "%d", &image->arr[j].red);
t = fscanf(fd, "%d", &image->arr[j].green);
t = fscanf(fd, "%d", &image->arr[j].blue);
j = j + 1;
}
return image;
}
PPM *loadPPMFromFile(char *filename) {
FILE *file;
/* TODO: step 1, open the file */
file = fopen("C:\\Users\\Olivia\\source\\repos\\f28hs-2020-21-cwk1-c\\PPMfiles", "r");
/* step 2: Check that file has been loaded correctly; show error otherwise*/
if (file != NULL) {
PPM *ppm;
/* ODO: step 3, get the PPM data from the file with the getPPM function */
getPPM(file);
if (ppm == NULL) {
/* TODO: step 4, display error if file cannot been parsed into a PPM struct*/
printf("File cannot be parsed.\n");
}
/* TODO: step 5, close the file */
fclose(file);
/* step 6: return the PPM */
return ppm;
} else {
fclose(file);
return NULL;
}
}
/*
Prints a PPM struct in the format of a PPM file
*/
void showPPM(PPM *ppm) {
printf("%s\n", ppm->format); //print format
//print comments
NODE *n = ppm->comments;
while (n->next != NULL) {
printf("%s\n", n->val);
n = n->next;
}
//print width, height and max
printf("%d %d\n%d\n", ppm->width, ppm->height, ppm->max);
//print the array containing the pixels
int j;
for (j = 0; j < ppm->height * ppm->width; ++j) {
printf("%d %d %d\n", ppm->arr[j].red, ppm->arr[j].green, ppm->arr[j].blue);
}
return;
}
/*
Encodes text into red field of PPM
Returns the encoded PPM
*/
PPM *encode(char *text, PPM *i) {
PPM *str = createPPM(i);
int random;
srand((unsigned)time(NULL));
int randMax = (i->height * i->width) / (strlen(text) + 1);
random = rand() % randMax;
if (random < 1) {
random = 1;
}
int k = 0;
int j = random;
//Red fields swapped with ASCII int
while (k < strlen(text)) {
if (str->arr[j].red == text[k]) {
j = j + 1; // if the values are the same we encode in the next pixel.
} else {
str->arr[j].red = text[k];
k = k + 1;
j = j + random;
}
}
return str;
}
/*
Compares 2 PPM structs and decodes the message hidden within
Returns the decoded message if the images have the same dimensions
Returns NULL otherwise
*/
char *decode(PPM *i1, PPM *i2) {
int i = 0;
int j = 0;
char *str = (char*)malloc(sizeof(char));
while (i < i1->height * i1->width) {
if (i1->arr[i].red != i2->arr[i].red) {
str[j] = i2->arr[i].red;
j = j + 1;
}
i = i + 1;
}
str = realloc(str, i);
return str;
printf("%s", str);
}
/* TODO: Question 3 */
int main(int argc, char *argv[]) {
/* check arguments */
switch (argc) {
case 2:
/* TODO: not enough arguments, print an error message */
printf("Not enough arguments. \n");
break;
case 3:
if (strcmp(argv[1], "e") == 0) { //Argument "e" - encode PPM
PPM *ppm = loadPPMFromFile(argv[2]);
createPPM(ppm);
/*Check that PPM is valid; continue if it is, exit otherwise */
if (ppm != NULL) {
PPM *encodedPPM;
/* TODO: encode the ppm with the text and assign to encodedPPM */
encodedPPM = encode(argv[2], encodedPPM);
/*Check that no error occured*/
if (encodedPPM == NULL) {
return EXIT_FAILURE;
} else {
/* TODO: print a confirmation that encoding was successful */
printf("Encoding successful. \n");
/* TODO: print the PPM to standard output with showPPM */
showPPM(encodedPPM);
return EXIT_SUCCESS;
}
} else {
return EXIT_FAILURE;
}
} else {
printf("Unrecognised or incomplete command line.\n");
return EXIT_FAILURE;
}
break;
case 4:
if (strcmp(argv[1], "d") == 0) { //Argument "d" - decode PPM
PPM *comparisonPPM;
PPM *encodedPPM;
/* TODO: get comparison file filename from argv, load it with
loadPPMFromFile then assign to comparisonPPM */
comparisonPPM = loadPPMFromFile(argv[2]);
/* TODO: get encoded file filename from argv, load it with
loadPPMFromFile then assign to encodedPPM */
encodedPPM = loadPPMFromFile(argv[2]);
/*Check both PPMs are valid; continue if so, exit otherwise */
if (comparisonPPM != NULL && encodedPPM != NULL) {
char *decodedMsg;
/* TODO: decode the encodedPPM with the comparisonPPM and assign to decodedMsg */
decodedMsg = decode(encodedPPM, comparisonPPM);
/*Check that the message has been decoded*/
if (decodedMsg != NULL) {
/* TODO: print a confirmation message that the message was decoded */
printf("Decoded message:\n");
/* TODO: print the decoded message */
printf("%p",decodedMsg);
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
} else {
return EXIT_FAILURE;
}
} else {
fprintf(stderr, "Unrecognised or incomplete command line.\n\n");
return EXIT_FAILURE;
}
break;
default:
fprintf(stderr, "Unrecognised or incomplete command line.\n\n");
return EXIT_FAILURE;
}
}
"Also in my main(), am I passing in the correct parameters?"
Yes, they are correct.
"not getting past the image format if statement in the getPPM function"
There are several issues with getPPM.
Overwriting c in the statements following this one:
char c = getc(fd);
is already covered in comments.
In the following:
sscanf(fd, "%s", image->format);
if (strcmp(image->format, "P3") != 0)
{
Because sscanf() will pick up the new line if there is one, strcmp() will fail the comparison for "P3".
Suggestions are to do 1 or more of the following:
running in a debugger, place a break point at the if and view value of image->format
place if(image->format != NULL) printf("%s", image->format) after sscanf()
if you suspect \n or \r\n may be in the buffer, use image->format[strcspn(image->format, "\r\n")] = 0; to remove them.
Regarding the following, suggest you read the documentation on each C function, eg fgets():
This:
fgets(fd, MAX_LEN, image->format);
scanf(...
Should be
if(fgets(image->format, MAX_LEN, fd) != NULL)
{
scanf(...
(Argument positions changed, and test before trying to use buffer.)
Aside: Because this is C, following malloc statements
PPM* image = (PPM*)malloc(sizeof(PPM));
image->format = (char*)malloc(MAX_LEN);
are more correctly written as
PPM* image = malloc(sizeof(*image));
image->format = malloc(MAX_LEN);
(Cast is removed from malloc() and note sizeof argument in the first statement. apply as applicable throughout your code.

Problem while opening a file in C on linux

I'm having problems with my C program which works perfectly on Windows but not on Linux. I use the following method for reading line by line a file:
char * getLineOfAnySize(FILE* fp, size_t typicalSize, int *endOfLineDetected,size_t *nrOfCharRead){
char *line; // buffer for our string
int ch; // we will read line character by character
size_t len = 0; // number of characters read (character counter)
size_t lineSize = typicalSize; // initial size of the buffer allocated for the line
*nrOfCharRead = 0;
if(!fp) return NULL; // protection
// allocating the buffer
line = realloc(NULL, sizeof(char)*lineSize); // expected size of the line is pathHead to typicalSize
if (!line) return line; // protection, if we fail to allocate the memory we will return NULL
while (1) { // loop forever
ch = fgetc(fp); // getting character by character from file
if (ch == '\n') break; // end of line detected - breaking the loop
if( ch == EOF) {
*endOfLineDetected = 1;
break; // end of file detected - breaking the loop
}
line[len++] = ch; // store the character in the line buffer, increase character counter
if (len == lineSize){ // we reached the end of line buffer (no more room)
lineSize = lineSize + 64; // we have to increase the line size
line = realloc(line, sizeof(char)*(lineSize)); // line buffer has new size now
if (!line) return line; // if we fail to allocate memory we will return NULL
}
if( (len == 0) && *endOfLineDetected){ // empty file
*endOfLineDetected = 1;
break;
}
}
line[len++] ='\0'; // ending the string (notice there is no '\n' in the string)
*nrOfCharRead = len;
return line; // return the string
}
The workflow of my program is the following: I gave in input a path, the file correspondent to the path contains in each line others file path that I read with the function above and put into a structure. On each i apply the KMP algorithm to get the occurrences of a string.
The problem comes in my program when I try to open the files that correspond to the paths I saved earlier:
FILE *fp = NULL;
fp = fopen(list->path, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", list->path);
exit(1);
}
On the screen is displayed:
, exiting ...
This is so weird because of file opening problem the output should be:
Cannot open "list->path content", exiting. . .
Even though I don't know why it gives me this error while opening the path read from the input file. During compiling there's no problem. I was thinking about buffer problems derived by the function "getLineOfAnySize. I'm not a Linux user, I was just trying to run the program in order to make sure it will run on both OS. Don't think about design issues or logical issues because on Windows everything works perfectly. Big up to everyone who will help me! Please ask further information about the code if needed.
EDIT:
The content of the input file is:
/home/xxx/Scrivania/find/try
/home/xxx/Scrivania/find/try1
Note that find is the directory of the project.
The following is a sample of my program in order to make more sense of variable and construct:
foo.c :
#include "foo.h"
FILE *fInput = NULL;
FILE *fp = NULL;
char *line1;
char *line2;
int endOfLineDetected = 0;
size_t nrOfCharRead = 0;
char ch;
fWord *w = NULL;
fWord *wordHead = NULL;
fWord *wordTail = NULL;
fList *list = NULL;
fList *listHead = NULL;
fList *listTail = NULL;
fPath *pathHead = NULL;
fPath *pathTail = NULL;
fPosition *positionHead = NULL;
fPosition *head = NULL;
fPosition *current = NULL;
char * getLineOfAnySize(FILE* fp, size_t typicalSize, int *endOfLineDetected,size_t *nrOfCharRead);
int main(int argc, char *argv[]){
fInput = fopen(argv[1], "r"); //the file that contains the path of the file in which search.
if(fInput == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", argv[1]);
exit(1);
}
while(!endOfLineDetected){ //read line by line the input file in order to save the path in a structure
line1 = getLineOfAnySize(fInput,128,&endOfLineDetected,&nrOfCharRead);
fList *node = malloc (sizeof(fList));
node->path = line1;
node->next = NULL;
if(listHead == NULL){
listHead = listTail = node;
}else{
listTail = listTail->next = node;
}
}
list = listHead;
fclose(fInput);
do{
fWord *app = malloc(sizeof(fWord));
printf("Insert the word to search: ");
scanf("%s", app->word);
app->totalOccurences = 0;
app->p = NULL;
app->next = NULL;
if(wordHead == NULL){
wordTail = wordHead = app;
}else{
wordTail = wordTail->next = app;
}
printf("Do you want to insert another word? (Y/N): ");
scanf(" %c", &ch);
}while(ch == 'y' || ch == 'Y');
w = wordHead;
while(w != NULL){
while(list != NULL){
w->p = malloc(sizeof(fPath));
w->p->fileOccurrences = 0;
w->p->path = list->path;
w->p->position = NULL;
w->p->next = NULL;
if(pathHead == NULL){
pathTail = pathHead = w->p;
}else{
pathTail = pathTail->next = w->p;
}
fp = fopen(w->p->path, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", w->p->path);
exit(1);
}
int countLine = 0;
endOfLineDetected = 0;
while(!endOfLineDetected){
line2 = getLineOfAnySize(fp,128,&endOfLineDetected,&nrOfCharRead);
int n = strlen(line2);
int m = strlen(w->word);
w->p->fileOccurrences = w->p->fileOccurrences + KMP(line2, w->word, n, m, countLine, w->p);
countLine = countLine + 1;
}
w->totalOccurences = w->totalOccurences + w->p->fileOccurrences;
w->p->position = getHead();
w->p = w->p->next;
list = list->next;
fclose(fp);
}
w->p = pathHead;
list = listHead;
w = w->next;
pathHead = NULL;
}
w = wordHead;
while(w != NULL){
printf("WORD %s \r\n", w->word);
printf("TOTAL %d \r\n", w->totalOccurences);
pathHead = w->p;
while(w->p != NULL){
printf("FILE %s \r\n", w->p->path);
printf("OCCURENCES %d \r\n", w->p->fileOccurrences);
positionHead = w->p->position;
while (w->p->position != NULL){
printf("%d %d\r\n", w->p->position->line, w->p->position->character);
w->p->position = w->p->position->next;
}
w->p->position = positionHead;
w->p = w->p->next;
}
w->p = pathHead;
w = w->next;
}
w = wordHead;
printf("\r\n");
freeMemory();
freeKMP();
return 0;
}
char * getLineOfAnySize(FILE* fp, size_t typicalSize, int
*endOfLineDetected,size_t *nrOfCharRead){
char *line; // buffer for our string
int ch; // we will read line character by character
size_t len = 0; // number of characters read (character counter)
size_t lineSize = typicalSize; // initial size of the buffer allocated for the line
*nrOfCharRead = 0;
if(!fp) return NULL; // protection
// allocating the buffer
line = realloc(NULL, sizeof(char)*lineSize); // expected size of the line is pathHead to typicalSize
if (!line) return line; // protection, if we fail to allocate the memory we will return NULL
while (1) { // loop forever
ch = fgetc(fp); // getting character by character from file
if (ch == '\n') break; // end of line detected - breaking the loop
if( ch == EOF) {
*endOfLineDetected = 1;
break; // end of file detected - breaking the loop
}
line[len++] = ch; // store the character in the line buffer, increase character counter
if (len == lineSize){ // we reached the end of line buffer (no more room)
lineSize = lineSize + 64; // we have to increase the line size
line = realloc(line, sizeof(char)*(lineSize)); // line buffer has new size now
if (!line) return line; // if we fail to allocate memory we will return NULL
}
if( (len == 0) && *endOfLineDetected){ // empty file
*endOfLineDetected = 1;
break;
}
}
line[len++] ='\0'; // ending the string (notice there is no '\n' in the string)
*nrOfCharRead = len;
return line; // return the string
}
// Function to implement KMP algorithm
int KMP(const char* X, const char* Y, int m, int n, int line, fPath *app){
int count = 0;
// next[i] stores the index of next best partial match
int next[n + 1];
for (int i = 0; i < n + 1; i++)
next[i] = 0;
for (int i = 1; i < n; i++){
int j = next[i + 1];
while (j > 0 && Y[j] != Y[i])
j = next[j];
if (j > 0 || Y[j] == Y[i])
next[i + 1] = j + 1;
}
for (int i = 0, j = 0; i < m; i++){
if(X[i] == Y[j]){
if (++j == n){
count = count + 1; //conta le occorrenze della parola nella riga in input
fPosition *node = malloc (sizeof(fPosition));
node->line = line;
node->character = i - j + 1;
node->next = NULL;
if(head == NULL){
current = head = node;
}else{
current = current->next = node;
}
app->position = current;
}
}
else if (j > 0) {
j = next[j];
i--; // since i will be incremented in next iteration
}
}
return count;
}
fPosition * getHead(){ //rimette il puntatore alla testa della lista
fPosition *app = head;
head = NULL;
return app;
}
void freeKMP(){
free(head);
free(current);
}
void freeMemory(){
list = listHead;
fList *tempL = NULL;
while(list != NULL){
tempL = list;
list = list->next;
free(tempL);
}
w = wordHead;
fWord *tempW = NULL;
fPath *tempP = NULL;
fPosition *tempO = NULL;
while(w != NULL){
while(w->p != NULL){
while(w->p->position != NULL){
tempO = w->p->position;
w->p->position = w->p->position->next;
free(tempO);
}
tempP = w->p;
w->p = w->p->next;
free(tempP);
}
tempW = w;
w = w->next;
free(tempW);
}
free(w);
free(line1);
free(line2);
free(wordHead);
free(wordTail);
free(listHead);
free(listTail);
free(pathHead);
free(pathTail);
free(positionHead);
}
foo.h:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct fileList{
char *path;
struct fileList *next;
};
struct filePath{
char *path;
int fileOccurrences;
struct OccurrencesPosition *position;
struct filePath *next;
};
struct fileWord{
char word[50];
int totalOccurences;
struct filePath *p;
struct fileWord *next;
};
struct OccurrencesPosition{
int line;
int character;
struct OccurrencesPosition *next;
};
typedef struct filePath fPath;
typedef struct fileWord fWord;
typedef struct OccurrencesPosition fPosition;
typedef struct fileList fList;
fPosition * getHead();
int KMP(const char* X, const char* Y, int m, int n, int line, fPath *app);
void freeMemory();
void freeKMP();
Maybe also the way I free memory isn't correct.
This is not a full answer, but a hint for further analysis.
I tested the program with the input file contents as shown in the question and entered one or two words.
If the first file does not exist, I get an error message as expected:
Cannot open /home/yuripaoloni/Scrivania/find/try, exiting. . .
Then I modified the input file to list two files that exist on my system and get an error message
Cannot open , exiting. . .
I extended the code that tries to open the file to get more output:
fp = fopen(w->p->path, "r");
if(fp == NULL){
fprintf(stderr, "Cannot open %s, exiting. . .\n", w->p->path);
perror("fopen");
exit(1);
} else {
printf("Successfully opened %s\n", w->p->path);
}
This prints
$ ./foo input
Insert the word to search: foo
Do you want to insert another word? (Y/N): y
Insert the word to search: bar
Do you want to insert another word? (Y/N): y
Insert the word to search: baz
Do you want to insert another word? (Y/N): n
Successfully opened /home/username/tmp/try
Successfully opened /home/username/tmp/try1
Cannot open , exiting. . .
fopen: No such file or directory
Apparently your program tries to open a third file after the existing file names. w->p->path might be a NULL pointer or may point to an empty string.
The same error occurs when I enter only one word. I did not further analyze the error.
To find out why your program tries to open a file with an empty name, you can run it in a debugger or add more output to see how many loop cycles are executed when processing the lists and which data you find.

Reading words from file error

I've got a problem with reading words from file and passing it to binary tree. When I debug it, it says:
Unhandled exception at 0x76E7773B(ntdll.dll) in Projekt.exe: 0.C00000005:
Access violation reading location 0x0037902A.
Here is the source code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
typedef struct Tree {
int val;
char *word;
struct Tree *left;
struct Tree *right;
} Tree;
void show(Tree *hd) {
if (hd != NULL) {
show(hd->left);
show(hd->right);
printf("%s -- %d\n", hd->word, hd->val);
}
}
void zero(Tree *aTree) {
if (aTree == NULL)
return;
zero(aTree->left);
free(aTree);
zero(aTree->right);
}
int alpha(char *word1, char *word2) {
if (word1[0] == 0 && word2[0] == 0)
return 2;
else
if (word1[0] == word2[0])
return alpha(&word1[1], &word2[1]);
else
if (word1[0] < word2[0])
return 1;
else
return 0;
}
Tree *create(char *word) {
Tree *temp;
temp = (Tree*)malloc(sizeof(Tree));
temp->left = temp->right = NULL;
temp->val = 1;
temp->word = (char*)malloc(sizeof(char));
strcpy(temp->word, word);
return temp;
}
Tree *insert(Tree *aTree, char *word) {
if (aTree == NULL) {
aTree = create(word);
} else
if (alpha(aTree->word, word) == 0) {
aTree->left = insert(aTree->left,word);
} else
if (alpha(aTree->word, word) == 1) {
aTree->right = insert(aTree->right, word);
} else
if (alpha(aTree->word, word) == 2) {
aTree->val++;
}
return aTree;
}
int main(int argc, char *argv[]) {
Tree *myTree = NULL;
char buffer[256] = { 0 };
char temp = 0;
int i = 0;
FILE *fp = fopen(argv[1], "r");
if (fp) {
while (temp != EOF) {
temp = getc(fp);
temp = toupper(temp);
if (temp >= 65 && temp <= 90) {
buffer[i] = temp;
i++;
} else {
if (buffer[0] != 0) {
puts(buffer);
myTree = insert(myTree, buffer);
memset(buffer, 0, sizeof(buffer));
i = 0;
}
}
}
}
fclose(fp);
show(myTree);
return 0;
}
Your program has several problems:
in function zero, you free the pointer too soon, you should move the free(aTree); as the last statement, otherwise you invoke undefined behavior, possibly a crash (but not the one you have, since you never call this function):
void zero(Tree *aTree) {
if (aTree != NULL) {
zero(aTree->left);
zero(aTree->right);
free(aTree);
}
In function alpha, you use recursion where a simple loop would suffice. The compiler may convert this to a loop, but it does have to. This is not a bug but why not use a more idiomatic approach such as:
int alpha(const char *word1, const char *word2) {
for (size_t i = 0;; i++) {
if (word1[i] == '\0' && word2[i] == '\0')
return 2;
if (word1[i] == word2[i])
continue;
if (word1[i] < word2[i])
return 1;
else
return 0;
}
}
In function create, you allocate a single byte for the string, this is definitely a cause for the crash. You should allocate strlen(word) + 1 or use strdup(word). You should not cast the return value of malloc() either:
Tree *create(const char *word) {
Tree *temp;
temp = malloc(sizeof(Tree));
temp->left = temp->right = NULL;
temp->val = 1;
temp->word = strdup(word);
return temp;
}
In function insert you call alpha multiple times, this is inefficient: you could use a switch statement:
Tree *insert(Tree *aTree, const char *word) {
if (aTree == NULL) {
return create(word);
switch (alpha(aTree->word, word)) {
case 0:
aTree->left = insert(aTree->left, word);
break;
case 1:
aTree->right = insert(aTree->right, word);
break;
case 2:
aTree->val++;
break;
}
}
return aTree;
}
function main has multiple issues:
You do not check if argv[1] is provided to the program. It would be NULL if the program is run without a command line argument.
Your test for end of file is incorrect: temp should be defined as int and you should test its value after reading the byte from the file with getc(), it is idiomatic to name c a variable used for this.
You should use character literals instead of hard coded ASCII values.
the test if (c >= 'A' && c <= 'Z') would work for ASCII, which is almost universal today, but it is more reliable to use isupper(c) instead.
You do not need to clear the buffer, setting a '\0' at the end before inserting the word is enough.
You should also check for buffer overflow and refuse to handle words longer than 255 characters.
You should not call fclose(fp) when fp is NULL, this is undefined behavior.
Here is a corrected version:
int main(int argc, char *argv[]) {
Tree *myTree = NULL;
char buffer[256];
int c;
size_t i;
FILE *fp;
if (argc < 2) {
printf("missing argument\n");
return 2;
}
fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("cannot open %s\n", argv[1]);
return 1;
}
i = 0;
while ((c = getc(fp)) != EOF) {
c = toupper(c);
if (isupper(c)) {
if (i < sizeof(buffer))
buffer[i] = c;
i++;
} else {
if (i > 0 && i < sizeof(buffer)) {
buffer[i] = '\0';
puts(buffer);
myTree = insert(myTree, buffer);
i = 0;
}
}
}
fclose(fp);
show(myTree);
return 0;
}

Incorrect code to check if a word can be made of smaller given words (word break)

Incorrect code to check if a word can be made of smaller given words (word break).This is the code I wrote for the above mentioned problem, however an online judge declares it as incorrect, what could be the possible reasons? And how should I modify my code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Node structure */
typedef struct node {
int letter[26];
struct node* next[26];
int is_word;
} node;
/* Create node */
node* getnode(void) {
node* p = malloc(sizeof(node));
int i;
for (i = 0; i < 1004; i++) {
p->letter[i] = 0;
p->next[i] = NULL;
}
p->is_word = 0;
return p;
}
/* make dictionary */
void fill_dictionary(char word[], node* start) {
int len = strlen(word), i;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[word[i] % 'a'] == 0) {
temp->letter[word[i] % 'a'] = 1;
temp->next[word[i] % 'a'] = getnode();
temp = temp->next[word[i] % 'a'];
} else {
temp = temp->next[word[i] % 'a'];
}
}
temp->is_word = 1;
return;
}
int spell_check(char line[100003], node* start) {
int len = strlen(line), i, flag = 0;
node* temp = start;
for (i = 0; i < len; i++) {
if (temp->letter[line[i] % 'a'] == 0) {
return 1;
} else {
temp = temp->next[line[i] % 'a'];
flag = 0;
if (temp->is_word == 1) {
flag = 1;
temp = start;
}
}
}
if (flag == 1) {
return 0;
} else {
return 1;
}
}
int main(void) {
int n, i, ans, m;
scanf("%d %d", &n,&m); // no. of words in dictionary
node* start = getnode();
for (i = 0; i < n; i++) {
char word[11]; // max length of dictionary word
scanf("%s", word);
fill_dictionary(word, start);
}
scanf("%d", &n); // no. of lines to be checked
for (i = 0; i < n; i++) {
char line[100003]; // max length of a line
scanf("%s", line);
ans = spell_check(line, start);
if (ans == 0) {
printf("YES\n");
} else {
printf("NO\n");
}
}
return 0;
}
Here's one way to to it. This compiles and runs. It displays the parsed result. It tries to read the dictionary from a file called "dictionary.text" in the current directory. You can change it to put the dictionary wherever you want. I commented it heavily to help you understand it but it has some subtle C things you may need to really think about and figure out. One bit of advice: Name everything in a program as extremely accurately for what it is/does as possible (but reasonably succinct). That will help immensely when trying to debug or figure out what you did wrong. Careless names really make code confusing and hard to debug.
Good luck!
Example:
$ gcc -o wordsplitter wordsplitter.c
$ wordsplitter xyzhellogoodbyefoodogcatpigcarwhereareyouhorse
xyz "hello" "goodbye" foo "dog" "cat" pigcar "where" "are" "you" horse
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DICTIONARY_FILEPATH "dictionary.txt"
#define MAX_WORD_SIZE 100
/*
* Error codes (usually this is put in a header file and included)
*/
#define SUCCESS 0
#define FILE_NOT_FOUND -1
#define OUT_OF_MEMORY -2
typedef struct word {
struct word *next;
char *word;
} word_t;
word_t *dictionaryListhead = NULL;
typedef struct wordsubcomponent {
struct wordsubcomponent *next;
char *text;
int isDictionaryWord;
} wordsubcomponent_t;
int
loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}
wordsubcomponent_t
*newsubcomponent() {
wordsubcomponent_t *subcomp = NULL;
if ((subcomp = calloc(sizeof(wordsubcomponent_t), 1)) != NULL) {
subcomp->text = strdup(""); // seed with empty string (instead of NULL) so we can append
} else {
fprintf(stderr, "out of memory (fatal). program exiting\n");
exit(-1);
}
return subcomp;
}
/*
* Returns an linked list of word subcomponents for the given word, split up around dictionary words
*/
wordsubcomponent_t *getWordSubcomponents(char *wordToParse, word_t *listhead) {
wordsubcomponent_t *subcomponents, *currSubcomp;
subcomponents = currSubcomp = newsubcomponent();
for (char *cp = wordToParse; cp < wordToParse + strlen(wordToParse);) { // exit when cp gets to end of word to parse.
int matchFlag = 0;
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
if (strncasecmp(cp, wordNode->word, strlen(wordNode->word)) == 0) { // prefix of cur. ptr is dict word.
if (strlen(currSubcomp->text) != 0) // Detected non-dict text in subcomp.
currSubcomp = currSubcomp->next = newsubcomponent(); // leave in list & add new subcomp for dict word.
currSubcomp->text = wordNode->word; // save dict-word in subcomp
currSubcomp->isDictionaryWord = 1;
currSubcomp = currSubcomp->next = newsubcomponent(); // dict-word in list, so get new subcomp
cp += strlen(wordNode->word); // advance cp past extracted dict-word
matchFlag = 1;
break; // break out of inner-loop
}
}
if (!matchFlag) { // No dict-word found at cp
char oneNullTerminatedLetter[2] = { *cp++, '\0' }; // put 1st ltr into NULL-terminated string & adv cp.
strcat(currSubcomp->text, oneNullTerminatedLetter); // append letter-as-string to curr subcomp
}
}
return subcomponents;
}
void
dumpDictionary(word_t *listhead) {
printf("\nList of dictionary words:\n");
printf("----------------\n");
for (word_t *wordNode = listhead; wordNode != NULL; wordNode = wordNode->next) {
printf(" %s\n", wordNode->word);
}
printf("----------------\n\n");
}
int
main(int argc, char **argv)
{
int status;
if ((status = loadDictionaryFromFile(DICTIONARY_FILEPATH, &dictionaryListhead)) < 0) {
switch(status) {
case FILE_NOT_FOUND:
fprintf(stderr, "Error accessing dictionary: %s\n", argv[0]);
break;
case OUT_OF_MEMORY:
fprintf(stderr, "Out of memory");
break;
}
return EXIT_FAILURE;
}
/*
* Load dictionary first so we can show them the list of words if they didn't
* pass in a command line argument with the word to parse.
*/
if (argc < 2) {
fprintf(stderr, "Usage: %s <word_to_parse>\n\n", argv[0]);
dumpDictionary(dictionaryListhead);
return EXIT_FAILURE;
}
wordsubcomponent_t *subcomp = getWordSubcomponents(argv[1], dictionaryListhead);
while(subcomp != NULL && strlen(subcomp->text) > 0) {
if (subcomp->isDictionaryWord)
printf("\"%s\" ", subcomp->text);
else
printf("%s ", subcomp->text);
subcomp = subcomp->next;
}
printf("\n");
return EXIT_SUCCESS;
}
#nerdist colony:
There is a resource leak in loadDictionaryFromFile. This means a file pointer was not closed when returning from this function in case of an error.
Here is a corrected copy of this function
int loadDictionaryFromFile(char *filename, word_t **listhead)
{
char wordFromFile[MAX_WORD_SIZE];
word_t *lastWordStored = NULL;
FILE *dictionaryFile = fopen(filename, "r");
if (dictionaryFile == NULL) {
return FILE_NOT_FOUND;
}
while(fgets(wordFromFile, sizeof(wordFromFile), dictionaryFile)) {
word_t *newDictionaryWordNode;
if ((newDictionaryWordNode = calloc(sizeof(word_t), 1)) == NULL) { // calloc automatically zeroes memory
fclose(dictionaryFile); // <-- Close the file pointer
return OUT_OF_MEMORY;
}
char *cp = strchr(wordFromFile, '\n');
if (cp != NULL)
*cp = '\0'; // get rid of trailing \n
newDictionaryWordNode->word = strdup(wordFromFile);
if (*listhead == NULL) {
lastWordStored = *listhead = newDictionaryWordNode;
} else {
lastWordStored = lastWordStored->next = newDictionaryWordNode;
}
}
fclose(dictionaryFile);
return SUCCESS;
}

strcmp() string from stdin and string from file [duplicate]

This question already has an answer here:
strcmp doesnt give 0, but the two args are the same
(1 answer)
Closed 8 years ago.
I have a problem with comparing string from file.
I want to create a list of words from a file which is a dictionary. I don't know why strcmp() return only -1 or 1 even when I use a word from my file. On output I have for example: 1somethingsomething instead of 0somethingsomething
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct words
{
char *word;
struct words *next;
};
void pushBack(struct words **headPointer, char string[])
{
struct words *pointer;
pointer = *headPointer;
if (*headPointer == NULL)
{
*headPointer = (struct words*)malloc(sizeof(struct words));
(*headPointer)->next = NULL;
(*headPointer)->word = (char*)malloc(sizeof(char)*(strlen(string)+1));
strcpy((*headPointer)->word, string);
}
else
{
while (pointer->next != NULL)
{
pointer = pointer->next;
}
pointer->next = (struct words*)malloc(sizeof(struct words));
pointer = pointer->next;
pointer->next = NULL;
pointer->word = (char*)malloc(sizeof(char)*(strlen(string)+1));
strcpy(pointer->word, string);
}
}
void createList(struct words **headPointer)
{
FILE *fp;
char string[80];
if ((fp = fopen("polski.txt", "rw")) == NULL)
{
printf ("Nie mogê otworzyæ pliku test.txt do zapisu!\n");
exit(-1);
}
else
{
while(fgets(string, 80, fp) != NULL)
{
pushBack(headPointer, string);
}
}
}
int seek(struct words *head, struct words **wordBeforePointer, struct words **wordAfterPointer)
{
char string[80];
printf("Type a word to seek:\n");
scanf("%s", string);
*wordBeforePointer = NULL;
*wordAfterPointer = NULL;
if (head != NULL)
{
if (strcmp(head->word, string) == 0)
{
return 1;
}
while(head->next != NULL)
{
head = head->next;
printf("%s", string);
printf("%s", head->word);
printf("%d", strcmp(head->word, string));
if (strcmp(head->word, string) == 0)
{
return 1;
}
}
}
return 0;
}
int main()
{
struct words *head, *wordBefore, *wordAfter;
head = NULL;
wordBefore = NULL;
wordAfter = NULL;
createList(&head);
printf("%d", seek(head, &wordBefore, &wordAfter));
return 0;
}
The fgets call does not actually remove the trailing newline, so people using this method frequently find that strcmp does not work simply because:
"thisword\n" != "thisword"
If you want to strip it manually, you can use something like:
while (fgets (inputLine, 80, filePtr) != NULL) {
// Get size of input line.
size_t strSize = strlen (inputLine);
// If there's a newline at the end, remove it.
if ((strSize > 0) && (inputLine[strSize-1] == '\n'))
inputLine[strSize-1] = '\0';
// Do whatever you need to "non-newline" line.
doSomethingWith (inputLine);
}

Resources