I'm fairly new to C and I can't seem to figure out what seems to be a pretty simple pointer problem. My program adds line numbers to a file. It reads in the file line by line and then adds a line number to the beginning of each line. It works fine on each file individually as you can see below:
soccer#soccer-Dell-DV051:~/code C$ ./a.out test.c
soccer#soccer-Dell-DV051:~/code C$ ./a.out miscellaneousHeader.h
soccer#soccer-Dell-DV051:~/code C$ ./a.out test.c miscellaneousHeader.h
*** Error in `./a.out': free(): invalid next size (normal): 0x08648170 ***
Segmentation fault (core dumped)
soccer#soccer-Dell-DV051:~/code C$
but when I run them together I get the above error. The following code is my program.
Compiler.c:
#include <stdio.h>
#include "lineNumAdderHeader.h"
#include "miscellaneousHeader.h"
int main(int argc, char *argv[]){
if (argc < 2)
fatal("in main(). Invalid number of arguments");
int i = 1;
while (i < argc){
lineNumAdder(argv[i]);
i++;
}
}
I have narrowed the problem to the lineNumPtr. The error occurs when lineNumPtr is freed after the second file. If lineNumPtr is not freed, which I know is bad programming, the program works just fine.
lineNumAdder.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "miscellaneousHeader.h"
#include "lineNumAdderHeader.h"
int lineSizeChecker(FILE*, int);
int lineNumChecker(char*);
int fileSizeChecker(FILE*);
void lineNumAdder(char* filename){
int lineSpace, position, lineNumCheckerBoolean, numOfDigits, fileSpace;
int lineNum = 1;
char *lineNumPtr = NULL;
char *numberedFile = NULL;
char *nonNumberedLine = NULL;
char *originalLine = NULL;
FILE *file = errorCheckedFopen(filename, "r+w");
while(1){
position = ftell(file);
if (position == 0){
fileSpace = fileSizeChecker(file);
numberedFile = errorCheckedMalloc(fileSpace);
}
lineSpace = lineSizeChecker(file, position);
if (position == 0)
originalLine = errorCheckedMalloc(lineSpace);
else
originalLine = realloc(originalLine, lineSpace);
if (fgets(originalLine, lineSpace, file) == NULL)
break;
lineNumCheckerBoolean = lineNumChecker(originalLine);
if (lineNumCheckerBoolean == 0){
if (position == 0)
nonNumberedLine = errorCheckedMalloc(lineSpace - 9);
else
nonNumberedLine = realloc(nonNumberedLine, lineSpace - 9);
strcpy(nonNumberedLine, &originalLine[9]);
}
else{
if (position == 0)
nonNumberedLine = errorCheckedMalloc(lineSpace);
else
nonNumberedLine = realloc(nonNumberedLine, lineSpace);
strcpy(nonNumberedLine, originalLine);
fileSpace += 8;
numberedFile = realloc(numberedFile, fileSpace);
}
numOfDigits = intDigitFinder(lineNum);
if (position == 0)
lineNumPtr = errorCheckedMalloc(numOfDigits);
else
lineNumPtr = realloc(lineNumPtr, numOfDigits);
sprintf(lineNumPtr, "%d", lineNum);
strcat(numberedFile, "/*");
strcat(numberedFile, lineNumPtr);
strcat(numberedFile, "*/");
if (lineNum < 10)
strcat(numberedFile, " ");
else if (lineNum >= 10 && lineNum < 100)
strcat(numberedFile, " ");
else if (lineNum >= 100 && lineNum < 1000)
strcat(numberedFile, " ");
else if (lineNum >= 1000 && lineNum < 10000)
strcat(numberedFile, " ");
strcat(numberedFile, nonNumberedLine);
lineNum++;
}
fclose(file);
free(originalLine);
free(nonNumberedLine);
free(lineNumPtr);
free(numberedFile);
}
int lineNumChecker(char *comment){
if (sizeOf(comment) < 8)
return 1;
if (comment[7] == '/' || comment[6] == '/' || comment[5] == '/' || comment[4] == '/')
return 0;
else
return 1;
}
int lineSizeChecker(FILE *file, int position){
int i = 2;
int ch;
while ((ch = fgetc(file)) != '\n' && ch != EOF)
i++;
fseek(file, position, SEEK_SET);
return i;
}
int fileSizeChecker(FILE *file){
int i = 2;
while (fgetc(file) != EOF)
i++;
fseek(file, 0, SEEK_SET);
return i;
}
miscellaneous.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "miscellaneousHeader.h"
void fatal(char*);
int sizeOf(char *data){
int i = 1;
while(data[i-1] != '\n')
i++;
return i;
}
void *errorCheckedMalloc(size_t size){
void *ptr = malloc(size);
if (ptr == NULL)
fatal("in errorCheckedMalloc(). Memory Allocation Failure\n");
else
return ptr;
}
FILE *errorCheckedFopen(char *filename, char *mode){
FILE *file = fopen(filename, mode);
if (file == NULL)
fatal("in errorCheckedFopen(). File Opening Failure\n");
else
return file;
}
void fatal(char *errorMessage){
char* completedErrorMessage = errorCheckedMalloc(sizeOf(errorMessage)+17);
strcpy(completedErrorMessage, "[!!] Fatal Error ");
strcat(completedErrorMessage, errorMessage);
perror(completedErrorMessage);
free(completedErrorMessage);
exit(-1);
}
int intDigitFinder(int num){
int digits = 0;
do {
num /= 10;
digits++;
} while (num != 0);
return digits;
}
void *reMalloc(void *ptr, size_t size){
char buf[strlen(ptr) + 1];
strcpy(buf, ptr);
free(ptr);
ptr = errorCheckedMalloc(size);
if(size >= strlen(buf))
strcpy(ptr, buf);
return ptr;
}
I apologize for the length. This is my first post and I wanted to make sure that I provided enough information for you guys to give me the best answers possible. Thank you for any and all answers. They are much appriciated.
Ok guys, so I have gotten it to work. I have tweaked the lineNumAdder.c file. The program now increases numberedFile's size by the line each time it is read in. Also the error was occuring on the second file because when I would strcat the line number into the malloced area junk was already stored there, so numberedFile would overflow. I have fixed this by using calloc instead of malloc. Thank you to all who gave answers and commented. They all helped tremendously.
Here is the completed lineNumAdder.c file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "miscellaneousHeader.h"
#include "lineNumAdderHeader.h"
int lineSizeChecker(FILE*, int);
int lineNumChecker(char*);
int fileSizeChecker(FILE*);
void lineNumAdder(char* filename){
int lineSpace, filePosition, lineNumCheckerBoolean, numOfDigits;
int fileSpace = 0;
int lineNum = 1;
char *lineNumPtr = NULL;
char *numberedFile = NULL;
char *nonNumberedLine = NULL;
char *originalLine = NULL;
FILE *file = errorCheckedFopen(filename, "r+w");
while(1){
filePosition = ftell(file);
lineSpace = lineSizeChecker(file, filePosition);
if (filePosition == 0)
originalLine = calloc(1, lineSpace);
else
originalLine = realloc(originalLine, lineSpace);
if (fgets(originalLine, lineSpace, file) == NULL)
break;
lineNumCheckerBoolean = lineNumChecker(originalLine);
if (lineNumCheckerBoolean == 0){
fileSpace += lineSpace;
if (filePosition == 0){
nonNumberedLine = calloc(1, lineSpace - 8);
numberedFile = calloc(1, fileSpace);
}
else{
nonNumberedLine = realloc(nonNumberedLine, lineSpace - 8);
numberedFile = realloc(numberedFile, fileSpace);
}
strcpy(nonNumberedLine, &originalLine[9]);
}
else{
fileSpace += lineSpace + 9;
if (filePosition == 0){
nonNumberedLine = calloc(1, lineSpace);
numberedFile = calloc(1, fileSpace);
}
else{
nonNumberedLine = realloc(nonNumberedLine, lineSpace);
numberedFile = realloc(numberedFile, fileSpace);
}
strcpy(nonNumberedLine, originalLine);
}
numOfDigits = intDigitFinder(lineNum);
if(filePosition == 0)
lineNumPtr = calloc(1, numOfDigits);
else
lineNumPtr = realloc(lineNumPtr, numOfDigits);
sprintf(lineNumPtr, "%d", lineNum);
strcat(numberedFile, "/*");
strcat(numberedFile, lineNumPtr);
strcat(numberedFile, "*/");
if (lineNum < 10)
strcat(numberedFile, " ");
else if (lineNum >= 10 && lineNum < 100)
strcat(numberedFile, " ");
else if (lineNum >= 100 && lineNum < 1000)
strcat(numberedFile, " ");
else if (lineNum >= 1000 && lineNum < 10000)
strcat(numberedFile, " ");
strcat(numberedFile, nonNumberedLine);
lineNum++;
}
fclose(file);
free(originalLine);
free(nonNumberedLine);
free(lineNumPtr);
free(numberedFile);
}
int lineNumChecker(char *comment){
if (sizeOf(comment) < 8)
return 1;
if (comment[7] == '/' || comment[6] == '/' || comment[5] == '/' || comment[4] == '/')
return 0;
else
return 1;
}
int lineSizeChecker(FILE *file, int position){
int i = 2;
int ch;
while ((ch = fgetc(file)) != '\n' && ch != EOF)
i++;
fseek(file, position, SEEK_SET);
return i;
}
int fileSizeChecker(FILE *file){
int i = 2;
while (fgetc(file) != EOF)
i++;
fseek(file, 0, SEEK_SET);
return i;
}
So, it's difficult to debug this... But at the very least:
int sizeOf(char *data) {
int i = 1;
while(data[i-1] != '\n' && data[i-1] != '\0')
i++;
return i;
}
Related
So I have this code which I was working on. The goal is to search for a string in a file and when that string is found it would return the corresponding values in that section of the file. So this is the file in question that is being searched:
So if it finds "AJ" then it would return all the values right up to "22550" and if it finds "TS" then it prints everything after "TS" and after "60500." This is my code in question:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
char *code;
int grpsize;
char route;
char *package;
//float fee;
float tcost;
float fcost;
} bookingrecord;
int main() {
FILE *fptr;
bookingrecord bookingrec;
char book_code[5];
printf("\n Please enter the code that corressponds to your record: ");
scanf("%s", book_code);
fptr = fopen("bookingdata", "r");
if (fptr == NULL) {
printf ("\nSorry we didn't find your file.");
exit (1);
}
ssize_t read;
char * line = NULL;
size_t len = 0;
int count = 0;
int found = 0;
while ((read = getline(&line, &len, fptr)) != -1) {
if (count == 0) {
bookingrec.code = line;
//printf("%s %s",bookingrec.code,book_code);
if (strcmp(bookingrec.code, book_code) == 0) {
found = 1;
}
} else if (count == 1 && found == 1) {
bookingrec.grpsize = line;
} else if (count == 2 && found == 1) {
bookingrec.route = line;
} else if (count == 3 && found == 1) {
bookingrec.fcost = strtof(line, NULL);
} else if (count == 4 && found == 1) {
bookingrec.name = line;
} else if (count == 5 && found == 1) {
bookingrec.package = line;
} else if (count == 6 && found == 1) {
bookingrec.tcost = strtof(line, NULL);
}
count = count + 1;
if(strlen(line) == 0) {
count = 0;
}
}
if (found == 1) {
printf("\n We have found your file");
printf("\n %s", bookingrec.code);
printf("\n %s", bookingrec.name);
printf("\n %d", bookingrec.grpsize);
printf("\n %s", bookingrec.route);
printf("\n %c", bookingrec.package);
printf("\n %.2f", bookingrec.tcost);
printf("\n %.2f", bookingrec.fcost);
}
fclose(fptr);
return 0;
}
The problem is that it only gives me this as the result:
So it finds the file okay but nothing happens so I uncomment a printf which I added to troubleshoot a bit right above my strcmp and get this when I enter for eg. "AJ":
I try another of the two character string. "SH" in this case and get this:
So it seems as if it is accepting any of the codes but prints the first line twice? But also discards everything else. I am a bit stumped as to what is happening. Any ideas?
Update:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
char *code;
int grpsize;
char *route;
char *package;
//float fee;
float tcost;
float fcost;
} bookingrecord;
int main() {
FILE *fptr;
bookingrecord bookingrec;
char book_code[5];
printf("\n Please enter the code that corressponds to your record: ");
scanf("%s", book_code);
fptr = fopen("bookingdata", "r");
if (fptr == NULL) {
printf ("\nSorry we didn't find your file.");
exit (1);
}
ssize_t read;
char * line = NULL;
size_t len = 0;
int count = 0;
int found = 0;
while ((read = getline(&line, &len, fptr)) != -1) {
line[strcspn(line, "\r\n")] = 0; //trims getLine
//printf("line is %s, count is %d \n", line, count);//debugging
if (count == 0) {
bookingrec.code = strdup(line);
if (strcmp(bookingrec.code, book_code) == 0) {
found = 1;
}
} else if (count == 1 && found == 1) {
char *tmp;
bookingrec.grpsize = strtol(strdup(line), NULL, 10);
} else if (count == 2 && found == 1) {
bookingrec.route = strdup(line);
} else if (count == 3 && found == 1) {
bookingrec.fcost = strtof(strdup(line), NULL);
} else if (count == 4 && found == 1) {
bookingrec.name = strdup(line);
} else if (count == 5 && found == 1) {
bookingrec.package = strdup(line);
} else if (count == 6 && found == 1) {
bookingrec.tcost = strtof(strdup(line), NULL);
}
count = count + 1;
if (found == 1 && count == 7){
break;
}
if(strlen(line) == 0) {
count = 0;
}
}
if (found == 1) {
printf("\n We have found your file");
printf("\n %s", bookingrec.code);
printf("\n %s", bookingrec.name);
printf("\n %d", bookingrec.grpsize);
printf("\n %s", bookingrec.route);
printf("\n %s", bookingrec.package);
printf("\n %.2f", bookingrec.tcost);
printf("\n %.2f", bookingrec.fcost);
}
fclose(fptr);
return 0;
}
Updated screens after edits:
I am currently completing my "Get_next_line" project. It is a function that reads a file and allows you to read a line ending with a newline character from a file descriptor. When you call the function again on the same file, it grabs the next line. This project deals with memory allocation and when to free and allocate memory to prevent leaks. The value (-1) is returned if an error occurred, (0) is returned if the file is finished reading, and (1) is returned if a line is read.
However, while testing my final code I encounter an abort when BUFFER_SIZE is between 8 and 15. This error only appears on Mac. Does anyone have an idea of what might be the issue?
Compile with :
gcc -Wall -Wextra -Werror -D BUFFER_SIZE=32 get_next_line.c get_next_line_utils.c
The get_next_line() function and some support code;
#include "get_next_line.h"
int ft_backslash(const char *s)
{
int i;
i = -1;
while (s[++i])
if (s[i] == '\n')
return (1);
if (s[i] == '\n')
return (1);
return (0);
}
int ft_read_buffer(int fd, char *buf)
{
int ret;
ret = 0;
ret = read(fd, buf, BUFFER_SIZE);
if (ret < 0)
return (-1);
buf[ret] = '\0';
return (ret);
}
char *ft_treat_save(char *save, char *buf)
{
char *tmp;
if (save == NULL)
save = ft_strdup(buf);
else
{
tmp = ft_strdup(save);
free (save);
save = ft_strjoin(tmp, buf);
free (tmp);
}
return (save);
}
char *ft_treat_tmp(char *save)
{
char *tmp;
tmp = ft_strdup(save);
free (save);
return (tmp);
}
int get_next_line(int fd, char **line)
{
int ret;
char buf[BUFFER_SIZE];
char *tmp;
static char *save;
ret = 1;
if (fd < 0 || fd > 255 || BUFFER_SIZE <= 0 || line == NULL)
return (-1);
*line = NULL;
tmp = NULL;
while (ret > 0)
{
if ((ret = ft_read_buffer(fd, buf)) < 0)
return (-1);
save = ft_treat_save(save, buf);
if (ft_backslash(save) == 1)
{
tmp = ft_treat_tmp(save);
*line = ft_strcut_front(tmp);
save = ft_strcut_back(tmp);
return (1);
}
}
tmp = ft_treat_tmp(save);
save = NULL;
*line = ft_strdup(tmp);
free (tmp);
return (0);
}
Other support code:
size_t ft_strlen(char *str)
{
size_t i;
i = 0;
if (str)
while (str[i])
i++;
return (i);
}
char *ft_strdup(char *str)
{
int i;
char *dst;
dst = malloc(sizeof(char) * ((ft_strlen(str) + 1)));
if (!(dst))
{
free (dst);
return (NULL);
}
i = -1;
while (str[++i])
dst[i] = str[i];
dst[i] = '\0';
return (dst);
}
char *ft_strjoin(char *s1, char *s2)
{
int i;
int j;
char *join;
i = -1;
j = 0;
if (!s1 && !s2)
return (NULL);
join = malloc(sizeof(char) * (ft_strlen(s1) + ft_strlen(s2) + 2));
if (!(join))
return (NULL);
if (BUFFER_SIZE == 1)
while (s1[++i + 1] != '\0')
join[i] = s1[i];
else
while (s1[++i] != '\0')
join[i] = s1[i];
while (s2[j])
join[i++] = s2[j++];
join[i] = '\0';
return (join);
}
char *ft_strcut_front(char *str)
{
int i;
char *front;
i = 0;
while (str[i] != '\n')
i++;
front = malloc(sizeof(char) * (i + 1));
if (!(front))
return (NULL);
i = 0;
while (str[i] != '\n')
{
front[i] = str[i];
i++;
}
front[i] = '\0';
return (front);
}
char *ft_strcut_back(char *str)
{
int i;
int j;
char *back;
i = 0;
while (str[i] != '\n')
i++;
i++;
back = malloc(sizeof(char) * ((ft_strlen(str) - i) + 1));
if (!(back))
return (NULL);
j = 0;
while (str[i] != '\0')
back[j++] = str[i++];
back[j] = '\0';
free (str);
return (back);
}
The main() function:
int main(void)
{
int fd, ret, line_count;
char *line;
line_count = 1;
ret = 0;
line = NULL;
fd = open("baudelaire.txt", O_RDONLY);
while ((ret = get_next_line(fd, &line)) > 0)
{
printf(" \n [ Return: %d ] | A line has been read #%d => |%s|\n", ret, line_count, line);
line_count++;
}
printf(" \n [ Return: %d ] A line has been read #%d: |%s\n", ret, line_count++, line);
printf("\n");
if (ret == -1)
printf("-----------\n An error happened\n");
else if (ret == 0)
{
printf("-----------\n EOF has been reached\n");
}
close(fd);
}
Problem solved. I forgot to add + 1 to my buf size... stupid error ! Thank you
This question already has answers here:
C read file line by line
(17 answers)
Closed 5 years ago.
I am new to c programming. I'm writing a program that reads a text file and stores in each line in into a char*[] data structures. I know how to this with characters, but I don't know how to store each line? does it require a 2D array? thats the code I have but I get segmentation error. I'm just trying to print out I and j to check if it works.
Thank you
#include <stdio.h>
#define NUMBER_LINES 400
int main()
{
char lines[NUMBER_LINES][255];
FILE *fp = fopen("input.txt", "r");
if (fp == 0)
{
return 1;
}
char c;
int i ;
while (fscanf (fp, "%c", &c) == 1)
{
i = 0;
int j;
for (j=0; !(c=='\n'); j++){
lines[i][j] = c;
}
if (c == '\n'){
printf("%s%s\n", lines[i][j]);
i++;
}
}
return 0;
}
You could use a matrix:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMBER_LINES 100
int main(void)
{
int i = 0;
char lines[NUMBER_LINES][255];
FILE *fp = fopen("file.txt", "r");
if (fp == 0)
{
fprintf(stderr, "failed to open input.txt\n");
exit(1);
}
while (i < NUMBER_LINES && fgets(lines[i], sizeof(lines[0]), fp))
{
lines[i][strlen(lines[i])-1] = '\0';
printf("\n%s", lines[i]);
i = i + 1;
}
fclose(fp);
return 0;
}
The code :
#include "get_next_line.h"
int check_n(char *str)
{
int i;
i = 0;
while (str && str[i])
{
if (str[i] == '\n')
return (i);
i++;
}
return (-1);
}
char *my_strdup_gnl(char *src)
{
int i;
char *str;
int ret;
i = 0;
if ((ret = check_n(src)) == -1)
return (NULL);
if ((str = malloc(sizeof(char) * ret + 1)) == NULL)
return (NULL);
while (i < ret)
{
str[i] = src[i];
i++;
}
str[i] = '\0';
return (str);
}
char *boucle_gnl(char *line, char *buff, int ret, int i)
{
strcat(line, buff);
i = 0;
while (buff[ret + 1] != '\0')
{
buff[i] = buff[ret + 1];
i++;
ret++;
}
buff[ret] = 0;
while (i < READ_SIZE + 1)
{
buff[i] = '\0';
i++;
}
return (line);
}
char *boucle_else_gnl(char *line, char *buff, int ret, int fd)
{
int i;
i = 0;
line = =strcpy(line, buff);
while (i < READ_SIZE + 1)
{
buff[i] = '\0';
i++;
}
if ((ret = read(fd, buff, READ_SIZE)) <= 0)
return (NULL);
return (line);
}
char *get_next_line(const int fd)
{
static char buff[READ_SIZE + 1] = {'\0'};
char *line;
int ret;
int i;
int tmp;
i = 0;
tmp = 0;
line = NULL;
if (!buff[0] && (ret = read(fd, buff, READ_SIZE)) <= 0)
return (NULL);
while (tmp++ != -1)
{
if ((line = my_realloc(line, (tmp * READ_SIZE))) == NULL)
return (NULL);
if ((ret = check_n(buff)) != -1)
return (line = boucle_gnl(line, buff, ret, i), line);
else
{
if ((line = boucle_else_gnl(line, buff, ret, fd)) == NULL)
return (NULL);
}
}
return (NULL);
}
The "my_realloc function" :
char *my_realloc(char *buff, int nb)
{
char *buf2;
int i;
i = 0;
if ((buf2 = malloc(sizeof(char) * (strlen(buff) + nb + 1))) == NULL)
return (NULL);
if (buff == NULL)
{
buf2[0] = '\0';
return (buf2);
}
while (buff[i])
{
buf2[i] = buff[i];
i++;
}
buf2[i] = '\0';
return (buf2);
}
The "get_next_line.h" :
#ifndef GET_NEXT_LINE_H_
# define GET_NEXT_LINE_H_
#ifndef READ_SIZE
# define READ_SIZE 10000
#include <unistd.h>
#include <stdlib.h>
#endif /* !READ_SIZE */
#endif /* !GET_NEXT_LINE_H_ */
I am trying to read a file. I want to read each line from the file and check if there are any spelling error in that line.
For that I have added condition that data from file will store in buffer until it gets a new line characher '\n'. And after getting this line I want to empty the buffer and re insert the values in that.
Code I am using for the same is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define W_COUNT 23800
#define MAX_LEN 100
char *dict[W_COUNT];
char buffer[MAX_LEN];
int num_words; //No of Words
char *statement[W_COUNT];
char buffer1[MAX_LEN];
void read_dictionary();
void file_read(char *);
void spell_check();
int word_search(char*);
int main(int argc, char*argv[]){
int i;
if(argc < 2){
printf("Expected Filename.\n");
exit(0);
}
read_dictionary();
file_read(argv[1]);
// spell_check();
}
void read_dictionary(){
FILE *fd;
int i = 0;
fd = fopen("dictionary", "r");
while ( fscanf(fd,"%s",buffer) != EOF)
dict[i++] = strdup(buffer);
num_words = i;
fclose(fd);
}
void file_read(char *filename){
FILE *fd;
int i = 0;
char c;
fd = fopen(filename,"r");
/*while ( fscanf(fd,"%s",buffer1) != EOF)
{
word[i++] = strdup(buffer1);
printf("File : %s\n", buffer1);
}*/
while ( ( c = fgetc(fd)) != EOF )
{
buffer1[i++] = tolower(c);
if ( c == '\n')
{
//printf("New Line\n");
spell_check();
buffer1[i] = 0;
}
//buffer1[i] = 0;
}
printf("Statement : %s\n", buffer1);
fclose(fd);
}
void spell_check(){
char *str;
str = strtok(buffer1," .?,!-");
while( str != NULL){
if(!word_search(str))
printf("%s Not found.\n",str);
str = strtok(0," .?,!-");
}
}
int word_search(char *word){
int high, low, mid;
high = num_words - 1;
low = 0;
int found = 0;
while (found == 0){
mid = (low + high) / 2;
if(strcmp(word, dict[mid]) == 0)
return 1;
else if(strcmp(word,dict[mid]) < 0)
high = mid - 1;
else
low = mid + 1;
if ( low > high)
return 0;
}
}
Any suggestions will be appreciated.
Thank you in advance.
while ( ( c = fgetc(fd)) != EOF )
{
buffer1[i++] = tolower(c);
if ( c == '\n')
{
//printf("New Line\n");
spell_check();
i = 0;
buffer1[i] = 0;
}
//buffer1[i] = 0;
}
For each line reading you have to assign the 0 to the i. After that you have to assign the null to the 0th position in the buffer.
You can try the above code for loop it will work.
I am having trouble debugging my implementation of Vigenere's cipher in C. The error arises when using file input (-f flag) where the file contains fewer than 6 chars (+ 1 EOF), it spits out some number of random characters as well as the expected input and I cannot figure out why this is, although I suspect it has something to do with the second part of my question which is, when using fread(), I noticed that this
if( fread(fcontents, fsize, sizeof(char), file) != 1 ) {...}
will run with no issues, whereas this
if( fread(fcontents, sizeof(char), fsize, file) != 1 ) {...}
doesn't work (i.e. causes fread() to return 1 and trigger the error handling code beneath it), which I would expect to be the other way around according to answers from here, but I may just be misinterpreting something.
My complete code is as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#define ENC 0 //Encrypt mode
#define DEC 1 //Decrypt mode
#define INP 0 //Commandline input mode
#define FLE 1 //File input mode
typedef struct {
char *password;
char *file_name;
char *input;
int edmode;
int ifmode;
} options;
void string_clean(char *source)
{
char *i = source;
char *j = source;
while(*j != 0) {
*i = *j++;
if( *i != ' ' && (isupper(*i) || islower(*i)) )
i++;
}
*i = 0;
}
char *ftostr(char *file_name) //Takes a file name as input and returns a char* to the files contents, returns NULL pointer on faliure. Allocated string must be freed after use by parent function to prevent memory leaks.
{
FILE *file;
long int fsize;
char *fcontents;
if( !(file = fopen(file_name, "r")) ) {
fprintf(stderr, "Error opening file \"%s\"!\n", file_name);
return NULL;
}
fseek(file, 0L, SEEK_END);
fsize = ftell(file);
rewind(file);
if( !(fcontents = malloc((fsize + 1) * sizeof(char))) ) {
fclose(file);
fprintf(stderr, "Error allocating memory!");
return NULL;
}
if( fread(fcontents, fsize, sizeof(char), file) != 1 ) { //suspected buggy line
fclose(file);
free(fcontents);
fprintf(stderr, "Error copying file to memory!\n");
return NULL;
}
fclose(file);
return fcontents;
}
options parse_opts(int argc, char *argv[])
{
int c;
options args;
args.edmode = ENC; //enable encrypt mode by default
args.ifmode = INP; //enable commandline input mode by default
args.file_name = NULL;
args.password = NULL;
args.input = NULL;
opterr = 0;
while((c = getopt(argc, argv, "dep:i:f:")) != -1) {
switch(c) {
case 'e':
args.edmode = ENC;
break;
case 'd':
args.edmode = DEC;
break;
case 'p':
args.password = optarg;
break;
case 'i':
args.input = optarg;
args.ifmode = INP;
break;
case 'f':
args.file_name = optarg;
args.ifmode = FLE;
break;
case '?':
if(optopt == 'f' || optopt == 'p' || optopt == 'i')
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
else if(isprint(optopt))
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
fprintf(stderr, "Usage: %s (-f file_name || -i input) -p password [options]\n"
"Optional: -e -d\n", argv[0]);
exit(-1);
}
}
return args;
}
char *vigenere_dec(char cipher_text[], char cipher[])
{
char *plain_text;
string_clean(cipher_text);
string_clean(cipher);
int plain_text_len = strlen(cipher_text);
int cipher_len = strlen(cipher);
if( !(plain_text = malloc((plain_text_len + 1) * sizeof(char))) )
return 0;
for(int i = 0; i < cipher_len; i++) {
if(isupper(cipher[i]))
cipher[i] -= 'A';
else if(islower(cipher[i]))
cipher[i] -= 'a';
}
for(int i = 0, j = 0; i < plain_text_len; i++, j++) {
if(j == cipher_len)
j = 0;
if(isupper(cipher_text[i]))
cipher_text[i] -= 'A';
else if(islower(cipher_text[i]))
cipher_text[i] -= 'a';
plain_text[i] = ((cipher_text[i] - cipher[j]) % 26);
if(plain_text[i] < 0)
plain_text[i] += 26;
plain_text[i] += 'A';
}
return plain_text;
}
char *vigenere_enc(char plain[], char cipher[])
{
char *cipher_text;
string_clean(plain);
string_clean(cipher);
int plain_len = strlen(plain);
int cipher_len = strlen(cipher);
if(plain_len == 0 || cipher_len == 0)
return NULL;
if( !(cipher_text = malloc((plain_len + 1) * sizeof(char))) )
return NULL;
for(int i = 0; i < cipher_len; i++) {
if(isupper(cipher[i]))
cipher[i] -= 'A';
else if(islower(cipher[i]))
cipher[i] -= 'a';
}
for(int i = 0, j = 0; i < plain_len; i++, j++) {
if(j == cipher_len)
j = 0;
if(isupper(plain[i]))
plain[i] -= 'A';
else if(islower(plain[i]))
plain[i] -= 'a';
cipher_text[i] = ((plain[i] + cipher[j]) % 26) + 'A';
}
return cipher_text;
}
int main(int argc, char *argv[])
{
options args;
char *output_text = NULL;
args = parse_opts(argc, argv);
if(args.password == NULL) {
fprintf(stderr, "Password uninitialised!\n");
exit(-1);
}
if(args.input == NULL && args.file_name == NULL) {
fprintf(stderr, "Input stream uninitialised!\n");
exit(-1);
}
if(args.ifmode == INP) {
if(args.edmode == ENC)
output_text = vigenere_enc(args.input, args.password);
else if(args.edmode == DEC)
output_text = vigenere_dec(args.input, args.password);
} else if(args.ifmode == FLE) {
if( !(args.input = ftostr(args.file_name)) )
return -1;
if(args.edmode == ENC)
output_text = vigenere_enc(args.input, args.password);
else if(args.edmode == DEC)
output_text = vigenere_dec(args.input, args.password);
free(args.input);
}
puts(output_text);
free(output_text);
return 0;
}
The fault is unterminated strings. You allowed room for the termination char with
if( !(plain_text = malloc(plain_text_len + 1)) ) // (simplified)
but after you have set, for example
plain_text[i] += 'A';
you need to end the string with
plain_text[i+1] = '\0';
or when the string is complete.
For the second part, you quoted another question, but failed to see that fread() returns the number of items read. So if you swap its size and count arguments, expect a different result (unless fsize == 1).
So you can either use
if( fread(fcontents, fsize, 1, file) != 1 ) {...}
or this
if( fread(fcontents, 1, fsize, file) != fsize ) {...}
Note I changed sizeof(char) to 1 since by definition, it is.