Base change program in C complies but does not show any output - c

I'm recently new to programming but this assignment has proven to be my most difficult. The program is suppose to read in a .txt file with the following format
input_base number output_base
and outputs the results. the bases can only range from 2-36 For example:
input: 2 10 4
output: 2
My program reads in each part of the line and stores them respectively. I then go through the steps to convert the number into the output base and then print it backwards. My problem is that the program runs fine and prints all the stored values and calculated values, but once I add in my "base_conversion" function the program no longer works and my friend even said it gave him a segmentation fault. I don't really know what could be causing it. Any help would be appreciated. Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void read_file_to_buffer(FILE *file);
char *buffer = NULL;
void string_check(char *buffer);
int char_to_int(char c);
int int_conversion(int x, int y);
void base_conversion(int end_number, int out_base);
int main(int argc, char *argv[]){
FILE *file = NULL;
if ( argc != 2 ){
fprintf(stderr, "Error: To many/few arguments\n");
exit(EXIT_FAILURE);
}
else {
file = fopen(argv[1], "rb");
if (file == NULL) {
fprintf(stderr, "Error: could not open file '%s'\n", argv[1]);
exit(EXIT_FAILURE);
}
else{
printf("File %s opened!\n", argv[1]);
}
}
read_file_to_buffer(file);
string_check(buffer);
fclose(file);
free(buffer);
buffer = NULL;
exit(EXIT_SUCCESS);
}
void read_file_to_buffer(FILE *file) {
long file_size = 0;
if(buffer != NULL){
fprintf(stderr, "buffer in use\n");
exit(EXIT_FAILURE);
}
rewind(file);
if (fseek(file, 0, SEEK_END) != 0){
perror("Could not seek to end of file");
exit(EXIT_FAILURE);
}
file_size = ftell(file);
if (file_size < 0){
perror("could not tell size of file");
exit(EXIT_FAILURE);
}
rewind(file);
buffer = (char *)malloc(sizeof(char) * (file_size + 1));
if (buffer == NULL){
fprintf(stderr, "Could not allocate memory");
exit(EXIT_FAILURE);
}
if(fread(buffer, sizeof(char), (size_t)file_size, file) != file_size){
fprintf(stderr, "Could not read file\n");
exit(EXIT_FAILURE);
}
buffer[file_size] = '\0';
return;
}
void string_check(char *buffer){
int i = 0;
int j = 0;
char base_in[2];
char number[50];
char base_out[2];
int actual_number[100];
int end_number = 0;
int x = 0;
int y = 0;
int in_base;
int out_base;
while( buffer[i] != '\0'){
if (buffer[i] != '#' && buffer[i] != ' ' && buffer[i] != '\n' && buffer[i] != '\r'){
while (buffer[i] != ' '){
base_in[j] = buffer[i];
i++;
j++;
}
j = 0;
i++;
if (base_in[1] != '\0'){
x = char_to_int(base_in[0]);
y = char_to_int(base_in[1]);
in_base = int_conversion(x, y);
x = 0;
y = 0;
}
else{
in_base = char_to_int(base_in[0]);
}
while (buffer[i] != ' '){
number[j] = buffer[i];
i++;
j++;
}
int q;
q=j;
j=0;
while (number[j] != '\0'){
actual_number[j] = char_to_int(number[j]);
end_number = end_number + pow(in_base, q-1) * actual_number[j];
j++;
q--;
}
j = 0;
i++;
while (buffer[i] != '\n' && buffer[i] != '\0'){
base_out[j] = buffer[i];
i++;
j++;
}
if (base_out[1] != '\0'){
x = char_to_int(base_out[0]);
y = char_to_int(base_out[1]);
out_base = int_conversion(x, y);
x = 0;
y = 0;
}
else{
out_base = char_to_int(base_out[0]);
}
j = 0;
i++;
base_conversion(end_number, out_base);
}
else{
while (buffer[i] != '\n' && buffer[i] != '\0'){
i++;
}
}
i++;
}
return;
}
int char_to_int(char c){
char map[] = "0123456789abcdefghijklmnopqrstuvwxyz";
int result = -1;
char *next = map;
while(*next != '\0'){
if(*next == c){
result = next - map;
break;
}
next++;
}
return result;
}
int int_conversion(int x, int y){
int value;
value = (x * 10) + y;
return value;
}
void base_conversion(int end_number, int out_base){
int remainder[100];
char map[] = "0123456789abcdefghijklmnopqrstuvwxyz";
int index = 0;
int i;
while (end_number != 0){
remainder[index] = end_number % out_base;
end_number = end_number / out_base;
index++;
}
for (i=0; i<index; i++){
printf("%c", map[remainder[index-1]]);
}
printf("\n");
return;
}

OP's base_conversion() is messed.
Loop prints same character repeatedly.
for (i=0; i<index; i++){
printf("%c", map[remainder[index-1]]); // Why same character?
}
Code is using signed math and % and can create negative remainders which may be used as array index.
remainder[index] = end_number % out_base; // result may be negative.
...
printf("%c", map[remainder[index-1]]); // accessing out of bounds with negative
Suggested simplification.
void base_conversion_helper(unsigned end_number, int out_base){
if (end_number >= out_base) base_conversion_helper(end_number/out_base, out_base);
putchar("0123456789abcdefghijklmnopqrstuvwxyz"[end_number % outbase]);
}
void base_conversion(unsigned end_number, int out_base){
assert(out_base >= 2 && out_base <= 36);
base_conversion_helper(end_number, out_base);
putchar('\n');
}

Related

Storing mac addresses and device names listed in a text file into a struct array using C

I am trying to take a list of MAC Addresses and Device names from a text file and store them in an array called list;
struct list {
char ch;
char a[2], b[2], c[2], d[2], e[2], f[2], g[2], alias[32]; //chars a-g are supposed to be a maximum of two characters long to store the different segments of the mac addresses, and the alias stores the device name up to 32 characters.
};
The main function here, as of right now is supposed to open the file "Inet.txt" and read each character individually using "char cur = fgetc." The function then assigns the different parts of the MAC address to its corresponding position in chars a-g of the list struct, and the alias char if the function goes more than 2 chars without reaching a ":" or a " ". The length of the current char is represented by the variable k, which increases every time the program detects a letter or a number, and is reset to -1 every time variable 'cur' is assigned to something. There is also an array "struct list *head[32]; " which stores each line separately, the line number being identified by the variable "int i", which increases by one every time "cur == '\n'" starting at "int = 0." The main function is as follows;
int main()
{
FILE *fp;
char cur, temp[32], temp2[32], p;
struct list *head[32];
head[0]=(struct list*)malloc(sizeof(struct list));
int num = 0, d, data, devices, i = 0, j = -1, k = -1, l = 0;
char arr[100][2];
int count = 0;
//head = current = NULL;
fp = fopen("Inet.txt", "r");
if(fp==NULL)
{
printf("Error opening file.");
}
while((cur = fgetc(fp)) != EOF)
{
//stringchecker(cur)!=0
if((cur >= 48 && cur <= 57)||(cur >= 97 && cur <= 122)||(cur >= 65 && cur <= 90))
{
k++; //counter for temp array size
if(cur >= 97 && cur <= 122)
{
temp[k] = cur-32;
}
else
{
temp[k] = cur;
}
if(k>1)
{
strncpy(temp2, temp, k+1);
temp2[k+1] = '\0';
aloc(&head[i],temp2,7);
// k = -1;
}
}
else if(cur == ':')
{
if(count == 0)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
else if(count == 1)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
else if(count == 2)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
else if(count == 3)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
else if(count == 4)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
else if(count == 5)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
count++;
k = -1;
}
else if(cur == ' ')
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,6);
k = -1;
}
else if(cur == '\n')
{
printf("\n%s:%s:%s:%s:%s%s\nALIAS: %s", (*head[i]).a,(*head[i]).b,(*head[i]).c,(*head[i]).d,(*head[i]).e,(*head[i]).f,(*head[i]).alias);
exit(0);
devices++;
data++;
count = 0;
num = -1;
i++;
j = -1;
k = -1;
head[i]=(struct list*)malloc(sizeof(struct list));
//exit(0);
}
}
fclose(fp);
return 0;
}
The "aloc()" function assigns the current char up to 16 characters to a-g or alias depending on the value of the variable count, which is a parameter of this function. The aloc() function is as follows;
void aloc(struct list **head, char ch[16], int count) //assigns ch value to specific variable of the current head based on the value of count 1-7
{
if(count == 0)
{
strncpy((*head)->a,ch, 2);
}
else if(count == 1)
{
strncpy((*head)->b,ch, 2);
}
else if(count == 2)
{
strncpy((*head)->c,ch, 2);
}
else if(count == 3)
{
strncpy((*head)->d,ch, 2);
}
else if(count == 4)
{
strncpy((*head)->e,ch, 2);
}
else if(count == 5)
{
strncpy((*head)->f,ch, 2);
}
else if(count == 6)
{
strncpy((*head)->g,ch, 2);
}
else if(count == 7)
{
strncpy((*head)->alias,ch, 16);
}
}
The input text file "Inet.txt" is as follows;
A0:FB:C5:44:b8:45 PLATTE
58:24:29:0f:c8:ee JET
F1:C0:11:16:53:1F Wabash
A0:FB:C5:32:15:10 GREEN
33:68:29:a1:b2:3c Charlie
58:24:29:0A:0B:C0 BAKER
GG:01:X0:99:1A:45 FOXTROT
The main problem I am having with this code is the variables a-g are not being assigned correctly. When I run the program to only read the first line, I get the following output:
A0FBC544B8:FBC544B8:C544B8:44B8:B8
ALIAS: PLATTE%
When the output should be:
A0:FB:C5:44:B8
ALIAS: PLATTE
I am not sure which line is causing the entire mac address to be assigned to char a of the current list. I will post the code as I have it in its entirety here to avoid confusion.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
struct list {
char ch;
char a[2], b[2], c[2], d[2], e[2], f[2], g[2], alias[32];
};
void aloc(struct list **head, char ch[16], int count)
{
if(count == 0)
{
strncpy((*head)->a,ch, 2);
}
else if(count == 1)
{
strncpy((*head)->b,ch, 2);
}
else if(count == 2)
{
strncpy((*head)->c,ch, 2);
}
else if(count == 3)
{
strncpy((*head)->d,ch, 2);
}
else if(count == 4)
{
strncpy((*head)->e,ch, 2);
}
else if(count == 5)
{
strncpy((*head)->f,ch, 2);
}
else if(count == 6)
{
strncpy((*head)->g,ch, 2);
}
else if(count == 7)
{
strncpy((*head)->alias,ch, 16);
}
}
int main()
{
FILE *fp;
char cur, temp[32], temp2[32], p;
struct list *head[32];
head[0]=(struct list*)malloc(sizeof(struct list));
int num = 0, d, data, devices, i = 0, j = -1, k = -1, l = 0;
char arr[100][2];
int count = 0;
//head = current = NULL;
fp = fopen("Inet.txt", "r");
if(fp==NULL)
{
printf("Error opening file.");
}
while((cur = fgetc(fp)) != EOF)
{
//stringchecker(cur)!=0
if((cur >= 48 && cur <= 57)||(cur >= 97 && cur <= 122)||(cur >= 65 && cur <= 90))
{
k++; //counter for temp array size
if(cur >= 97 && cur <= 122)
{
temp[k] = cur-32;
}
else
{
temp[k] = cur;
}
if(k>1)
{
strncpy(temp2, temp, k+1);
temp2[k+1] = '\0';
aloc(&head[i],temp2,7);
// k = -1;
}
}
else if(cur == ':')
{
if(count == 0)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
else if(count == 1)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
else if(count == 2)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
else if(count == 3)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
else if(count == 4)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
else if(count == 5)
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,count);
}
count++;
k = -1;
}
else if(cur == ' ')
{
strncpy(temp2, temp, 2);
temp2[2] = '\0';
aloc(&head[i],temp2,6);
k = -1;
}
else if(cur == '\n')
{
printf("\n%s:%s:%s:%s:%s%s\nALIAS: %s", (*head[i]).a,(*head[i]).b,(*head[i]).c,(*head[i]).d,(*head[i]).e,(*head[i]).f,(*head[i]).alias);
exit(0);
devices++;
data++;
count = 0;
num = -1;
i++;
j = -1;
k = -1;
head[i]=(struct list*)malloc(sizeof(struct list));
//exit(0);
}
}
fclose(fp);
return 0;
}
I initially tried writing this program using linked lists, but I thought it would be easier to keep track of an array of list structs for use later in my program. However I keep getting the same problem with my output. Any help is appreciated.
If you remove exit(0); from the block here
else if(cur == '\n')
{
printf(/* ... */);
exit(0);
devices++;
data++;
count = 0;
/* ... */
then this program appears to work1.
I say "appears" because this program invokes Undefined Behaviour by printing non null-terminated buffers with the printf specifier %s.
You need to either specify a precision, being the maximum number of bytes to print, with each %s specifier. For example:
#include <stdio.h>
int main(void)
{
char buf[2] = "AB"; /* the null byte is not stored */
printf("%2s\n", buf);
}
Or, you need to ensure your buffers are large enough to store a desired string length plus the null-terminating byte. If you want to store a string of length 2, your buffer must be at least of size 3.
#include <stdio.h>
int main(void)
{
char buf[3] = "AB"; /* the null byte IS stored */
printf("%s\n", buf);
}
Note that strncpy is notoriously hard to use, as it does not null-terminate the buffer if the length of the source string is greater than or equal to the size provided.
1. You must also change char cur to int cur. On platforms when char is an unsigned type, you will not be able to reliably test against the negative int value of EOF. fgetc returns an int for this reason.
As pointed out in the comments, avoid magic numbers and instead use the functions found in <ctype.h>.
If your file contents are predictably formatted, you can just use fgets + sscanf to read each line. For example:
#include <stdio.h>
#include <stdlib.h>
#define MAX_ADDRS 256
struct address {
char a[3];
char b[3];
char c[3];
char d[3];
char e[3];
char f[3];
char alias[32];
};
size_t read_macs(struct address *addrs, size_t limit, FILE *f)
{
char buffer[512];
size_t n = 0;
while (n < limit && fgets(buffer, sizeof buffer, f)) {
int cv = sscanf(buffer, "%2s:%2s:%2s:%2s:%2s:%2s%31s",
addrs[n].a, addrs[n].b, addrs[n].c,
addrs[n].d, addrs[n].e, addrs[n].f,
addrs[n].alias);
if (7 == cv)
n++;
}
return n;
}
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "usage: %s FILENAME\n", *argv);
return EXIT_FAILURE;
}
FILE *file = fopen(argv[1], "r");
if (!file) {
perror(argv[1]);
return EXIT_FAILURE;
}
struct address store[MAX_ADDRS];
size_t length = read_macs(store, MAX_ADDRS, file);
fclose(file);
for (size_t i = 0; i < length; i++)
printf("%s (%s:....:%s)\n",
store[i].alias, store[i].a, store[i].f);
}
$ ./a.out Inet.txt
PLATTE (A0:....:45)
JET (58:....:ee)
Wabash (F1:....:1F)
GREEN (A0:....:10)
Charlie (33:....:3c)
BAKER (58:....:C0)
FOXTROT (GG:....:45)

Why on while(getchar()!=EOF) it iterates extra time?

I'm trying to count chars from input, and I noticed that while(getchar()!=EOF) produces an extra count, Is it because it counts the null-terminated from input?
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define LINE 5
#define MEM_SIZE 10
char *getInput(int *counter);
void printInput(char *input);
int main() {
char *mainInput;
int counter = 0;
printf("Please enter your input:\n");
mainInput = getInput(&counter);
if (mainInput == NULL) {
return 1;
}
printf("\n\n\nOutput:\n%s\n", mainInput);
printf("number of chars: %d\n", counter);
printInput(mainInput);
free(mainInput);
return 0;
}
char *getInput(int *counter) {
char *p = (char *)malloc(MEM_SIZE * sizeof(char));
char *q = p; /* backup pointer, if realloc fails to allocate, function will return last address values stored */
int c;
int temp_counter = 0;
long current = 0, last = MEM_SIZE - 1;
while ((c = getchar()) != EOF) {
if (current >= last) {
q = p;
p = (char *)realloc(q, last + (MEM_SIZE * sizeof(char)));
if (p == NULL) {
printf("Memory allocation failed, printing only stored values \n");
return q;
}
last += MEM_SIZE;
}
p[current] = c;
temp_counter++;
printf("number of chars: %d\n", temp_counter);
++current;
}
p[current] = '\0';
(*counter) = temp_counter - 1;
return p;
}
void printInput(char *input) {
int i, j = 0;
while (input[j] != '\0') {
for (i = 0; i < LINE; i++) {
if (input[j] == '\0')
break;
putchar(input[j]);
++j;
}
if (input[j] != '\0')
putchar('\n');
}
}

How to parse bigger amount of words?

I have a program, which receives filename as an input, saves file contents into 2d char array and then outputs words. It works absolutely fine for about 400 words, but then, when I add more words, it crashes. Debugging showed that i am trying to access unused address, and I don't understand how is that possible considering that previous tests with lesser amount of words were successful.
The question is: what am i missing here?
FILE: functions.c
#include "Lab10.h"
#include <stdio.h>
#include <malloc.h>
char** parser(char* filename) {
FILE* fp;
fp = fopen(filename, "r");
char** str = (char**)calloc(N, sizeof(char*) * N);
if (!str)
{
printf("\n Allocation error");
return NULL;
}
char ch;
int space = 0, words = 0;
for (int i = 0; !feof(fp); i++) // Memory allocation
{
ch = fgetc(fp);
if (!is_ch(ch))
{
if (i != space)
{
if (!(str[words] = (char*)calloc(i - space, sizeof(char) * (i - space))))
{
printf("\n Allocation error");
return NULL;
}
words++;
}
while (!is_ch(ch) && !feof(fp))
{
ch = fgetc(fp);
i++;
}
if(!feof(fp))
fseek(fp, -(int)sizeof(char), 1);
i--;
space = i;
}
}
fseek(fp, 0, SEEK_SET);
for (int i = 0; i < words; i++) // Copying words into 2d array
{
while (!is_ch(fgetc(fp)));
if (!feof(fp))
fseek(fp, -(int)sizeof(char), 1);
int j = 0;
do {
if (((fscanf(fp, "%c", &str[i][j])) != 1))
break;
j++;
} while (is_ch(str[i][j-1]) && !feof(fp));
}
return str;
}
int is_ch(char ch)
{
return ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'));
}
FILE: main.c
#define _CRT_SECURE_NO_WARNINGS
#include "Lab10.h"
#include <stdio.h>
#include <stdlib.h>
int main() {
char* filename = (char*)malloc(sizeof(char) * N);
if (!scanf("%s", filename) || filename == 0)
{
printf("\n Incorrect filename input");
return -1;
}
char** str = parser(filename);
printf("\n Contents of .txt file:");
for (int i = 0; str[i] != NULL; i++) {
printf("\n\t%d) ", i+1);
for (int j = 0; is_ch(str[i][j]); j++) {
printf("%c", str[i][j]);
}
}
return 0;
}
This answer was posted as a reply to one of the comments below the question itself. I tried writing readWord function, which recieves filepointer, reads one word and then returns pointer to the resulting array - that's eases the procedure, making it less complex. It works almost like fgets(), but it reads till non-character, instead of a newline
readWord function itself:
char* readWord(FILE* fp) {
char ch = 0;
while (!is_ch(ch))
{
ch = fgetc(fp);
if (ch == EOF || !ch)
return NULL;
}
int size = 1;
while (is_ch(ch))
{
if ((ch = fgetc(fp)) == EOF || !ch)
break;
size++;
}
fseek(fp, -(size * (int)sizeof(char)), 1);
if (ch != EOF || !ch)
size--;
char* word = (char*)calloc(size, sizeof(char) * size + 1);
if (!word)
{
printf("\n Allocation error.");
return NULL;
}
for (int i = 0; i < size; i++)
word[i] = fgetc(fp);
word[size] = '\0';
return word;
}
That's how i use it in main():
FILE* fp = fopen("test.txt", "r");
char* word;
while ((word = readWord(fp)) != NULL)
{
for (int i = 0; word[i] != '\0'; i++)
printf("%c", word[i]);
printf(" ");
}
Is there is anything i need to improve here? It works fine, but is it possible to somehow make it better?

To mimic sort command of linux, to sort lines of a text file

Sort command of linux must sort the lines of a text file and transfer the output to another file. But my code gives a runtime error. Please rectify the pointer mistakes so that output.
In which line exactly should I make changes? Because there is no output after all.
I'm pasting the whole code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sortfile(char **arr, int linecount) {
int i, j;
char t[500];
for (i = 1; i < linecount; i++) {
for (j = 1; j < linecount; j++) {
if (strcmp(arr[j - 1], arr[j]) > 0) {
strcpy(t, arr[j - 1]);
strcpy(arr[j - 1], arr[j]);
strcpy(arr[j], t);
}
}
}
}
int main() {
FILE *fileIN, *fileOUT;
fileIN = fopen("test1.txt", "r");
unsigned long int linecount = 0;
int c;
if (fileIN == NULL) {
fclose(fileIN);
return 0;
}
while ((c = fgetc(fileIN)) != EOF) {
if (c == '\n')
linecount++;
}
printf("line count=%d", linecount);
char *arr[linecount];
char singleline[500];
int i = 0;
while (fgets(singleline, 500, fileIN) != NULL) {
arr[i] = (char*)malloc(500);
strcpy(arr[i], singleline);
i++;
}
sortfile(arr, linecount);
for (i = 0; i < linecount; i++) {
printf("%s\n", arr[i]);
}
fileOUT = fopen("out.txt", "w");
if (!fileOUT) {
exit(-1);
}
for (i = 0; i < linecount; i++) {
fprintf(fileOUT, "%s", arr[i]);
}
fclose(fileIN);
fclose(fileOUT);
}
The problem in your code is you do not rewind the input stream after reading it the first time to count the number of newlines. You should add rewind(fileIN); before the next loop.
Note however that there are other problems in this code:
the number of newline characters may be less than the number of successful calls to fgets(): lines longer than 499 bytes will be silently broken in multiple chunks, causing more items to be read by fgets() than newlines. Also the last line might not end with a newline. Just count the number of successful calls to fgets().
You allocate 500 bytes for each line, which is potentially very wasteful. Use strdup() to allocate only the necessary size.
Swapping the lines in the sort routine should be done by swapping the pointers, not copying the contents.
allocating arr with malloc is safer and more portable than defining it as a variable sized array with char *arr[linecount];
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sortfile(char **arr, int linecount) {
for (;;) {
int swapped = 0;
for (int j = 1; j < linecount; j++) {
if (strcmp(arr[j - 1], arr[j]) > 0) {
char *t = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = t;
swapped = 1;
}
}
if (swapped == 0)
break;
}
}
int main() {
FILE *fileIN, *fileOUT;
char singleline[500];
int i, linecount;
fileIN = fopen("test1.txt", "r");
if (fileIN == NULL) {
fprintf(stderr, "cannot open %s\n", "test1.txt");
return 1;
}
linecount = 0;
while (fgets(singleline, 500, fileIN)) {
linecount++;
}
printf("line count=%d\n", linecount);
char **arr = malloc(sizeof(*arr) * linecount);
if (arr == NULL) {
fprintf(stderr, "memory allocation failure\n");
return 1;
}
rewind(fileIN);
for (i = 0; i < linecount && fgets(singleline, 500, fileIN) != NULL; i++) {
arr[i] = strdup(singleline);
if (arr[i] == NULL) {
fprintf(stderr, "memory allocation failure\n");
return 1;
}
}
fclose(fileIN);
if (i != linecount) {
fprintf(stderr, "line count mismatch: i=%d, lilnecount=%d\n",
i, linecount);
linecount = i;
}
sortfile(arr, linecount);
for (i = 0; i < linecount; i++) {
printf("%s", arr[i]);
}
fileOUT = fopen("out.txt", "w");
if (!fileOUT) {
fprintf(stderr, "cannot open %s\n", "out.txt");
return 1;
}
for (i = 0; i < linecount; i++) {
fprintf(fileOUT, "%s", arr[i]);
}
fclose(fileOUT);
for (i = 0; i < linecount; i++) {
free(arr[i]);
}
free(arr);
return 0;
}
To get a different sort order, you would change the comparison function. Instead of strcmp() you could use this:
#include <ctype.h>
int my_strcmp(const char *s1, const char *s2) {
/* compare strings lexicographically but swap lower and uppercase letters */
unsigned char c, d;
while ((c = *s1++) == (d = *s2++)) {
if (c == '\0')
return 0; /* string are equal */
}
/* transpose case of c */
if (islower(c)) {
c = toupper(c);
} else {
c = tolower(c);
}
/* transpose case of d */
if (islower(d)) {
d = toupper(d);
} else {
d = tolower(d);
}
/* on ASCII systems, we should still have c != d */
/* return comparison result */
if (c <= d)
return -1;
} else {
return 1;
}
}

How can I get my Lexical analyzer program to print out more than just seperators?

Im writing a Lexical analyzer to read from a file and describe the text as either identifiers, keywords, separators, or operators. For some reason I am only able to output the separators, unless I delete or comment out the while loop with the print statement for the separators. When I delete that, the program prints out everything else correctly, skipping over the separators.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
int isKeyword(char buffer[]){
char keywords[32][10] = {"auto","break","case","char","const","continue","default",
"do","double","Else","enum","Function","Float","for","goto",
"If","Integer","long","register","Return","short","signed",
"sizeof","static","struct","switch","typedef","union",
"DOWhile","void","Write","while"};
int i, flag = 0;
for(i = 0; i < 32; ++i){
if(strcmp(keywords[i], buffer) == 0){
flag = 1;
break;
}
}
int k, flag2 = 0;
for (k = 0; k<32; ++k){
if(strcmp(keywords[i], buffer) == 0){
flag2 = 1;
break;
}
}
return flag;
return flag2;
}
int main(){
char ch, buffer2[15], operators[] = "+-*/%=";
char ch2, buffer[15], seperators[] = "{}(),;";
FILE *fp;
int i,k,j=0;
fp = fopen("input.txt","r");
if(fp == NULL){
printf("error while opening the file\n");
exit(0);
}
while((ch = fgetc(fp)) != EOF){
for(i = 0; i < 6; ++i){
if(ch == operators[i])
printf("%c is operator\n", ch);
while((ch2 = fgetc(fp)) != EOF){
for(k = 0; k < 6; ++k){
if(ch2 == seperators[k])
printf("%c is seperator\n", ch2);
}
}
if(isalnum(ch)){
buffer[j++] = ch;
}
else if((ch == ' ' || ch == '\n') && (j != 0)){
buffer[j] = '\0';
j = 0;
if(isKeyword(buffer) == 1)
printf("%s is keyword\n", buffer);
else
printf("%s is indentifier\n", buffer);
}
}
}
fclose(fp);
return 0;
}
The problem seems to be the second while loop containing the separator instructions, but I cant seem to figure out how to print that along with everything else.
I think this may help.There is no reason to create an additional char ch, or the buffer, when creating the separators. Just add it onto the end of the previous line. I just split it with a comma.This will clean your code up and allow you to keep the separators with the rest of the while loop code.
#include <stdio.h>
#define KEY 32
#define BUFFER_SIZE 15
int isKeyword(char buffer[])
{
char keywords[KEY][10] = { "auto","break","case","char","const","continue","default", "do","double","else","enum","extern","float","for","goto",
"if","int","long","register","return","short","signed", "sizeof","static","struct","switch","typedef","union", "unsigned","void","volatile","while"};
int i, flag = 0;
for (i = 0; i < KEY; ++i)
{
if (strcmp(keywords[i], buffer) == 0)
{
flag = 1;
break;
}
}
return flag;
}
int main()
{
char ch, buffer[BUFFER_SIZE], operators[] = "+-*/%=", separators[] = "(){}[]<>,";
FILE *fp;
int i, j = 0;
fp = fopen("Text.txt", "r");
while ((ch = fgetc(fp)) != EOF)
{
for (i = 0; i < 6; ++i)
{
if (ch == operators[i])
{
printf(" OPERATOR: %c \n", ch);
}
else if (ch == separators[i])
printf(" SEPARATOR: %c \n", ch);
}
if (isalnum(ch))
{
buffer[j++] = ch;
}
else if ((ch == ' ' || ch == '\n') && (j != 0))
{
buffer[j] = '\0';
j = 0;
{
if (isKeyword(buffer) == 1)
printf(" KEYWORD: %s \n", buffer);
else
printf(" IDENTIFIER: %s \n", buffer);
}
}
}
fclose(fp);
return 0;
}

Resources