0

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;
}
LEKrensta
  • 11
  • 2
  • 2
    Run it in a debugger. You'll be told *exactly* where the fault is with near-certainty. – WhozCraig Feb 14 '17 at 23:41
  • I did this shortly after. Though I still don't understand whats happening. It says its caused on the line where base_in[j] = buffer[i]; – LEKrensta Feb 14 '17 at 23:52
  • That isn't the only problem. There is a number of issues in your `string_check` function. That needs to be reviewed *very* carefully. You should single-step through that function and watch your variables to ensure it does what you think it does (from what I see, I know what you want it to do, and it isn't doing it). – WhozCraig Feb 14 '17 at 23:54
  • The program is also suppose to skip over "useless lines" that are comments that start with '#' or blank lines – LEKrensta Feb 14 '17 at 23:57
  • Tracing through many times the values are what I want them to be. The problem comes in when I enter the base conversion function. If I get rid of that function it works for me and stores the correct values. – LEKrensta Feb 15 '17 at 00:02
  • Really? Because when I throw out all the file io, the dynamic buffer, etc. and just use `char buffer[] = "2 10 4";` as the data to process, neither `string_check` nor `base_conversion` work correctly (the latter because of the former). How did you "trace through" *past* the line you claim your debugger says a fault happens on? You were running your debugger and single stepping, *right* ? – WhozCraig Feb 15 '17 at 00:05
  • I'm tracing it very carefully by hand and by my debugger. I even put in print statements throughout string_check to make sure the right values are being used. But once I place in base_conversion everything goes haywire. I don't even know where to begin. I realize after doing a lot of this I could have done it a bunch of simpler ways but I'm to far in to restart and don't have the time. – LEKrensta Feb 15 '17 at 00:11

1 Answers1

0

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');
}
Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256