0

I am trying to write a program to convert a hexadecimal number to a decimal, and then print the decimal value. The problem I am facing is that my for loop causes a segmentation fault.

  printf("no segmentation fault so far..."); /*this printed*/
  for (i=0; (c=getchar()) != '\n'; i++) {
    printf("no segmentation fault after entering for loop"); /*this didn't print*/

I know this because as you can see from my code above all the code before the for loop were ran but the body wasn't executed. There could be a possibility that the for loop test case was not met and therefore it was skipped. To test for this, I put printf statements in other parts of my program as well. However, only the one above the for loop was executed. Here's my full code if it helps:

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#define MAXLEN 100

int htoi(char *s, int lim);
void copy(char *to, char *from);

int main(void) {
  char *hexArray = (char *)malloc(MAXLEN);
  htoi(hexArray, MAXLEN);
  return 0;
}

int htoi(char s[], int lim) {
  double decOutput;
  int i = 0;
  int c;
  int size = MAXLEN;
  printf("no segmentation fault so far...");
  for (i=0; (c=getchar()) != '\n'; i++) {
    printf("no segmentation fault after entering for loop");
    if (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
      if(i >= size - 1) {
        size = size + MAXLEN;
        char *tmp = (char *)malloc(size);
        copy(tmp, s);
        free(s);
        s = tmp;
        printf("Buffer size increased to %d\n", size);
      }
      s[i] = c;
    }
    else {
      printf("INVALID INPUT!!! Decimal output may be inaccurate.");
    }
  }

  printf("exited loop");

  for(i = 0; s[i] != '\0'; i++) {
    printf("entered second for loop");
    if (s[i] != '0' || (s[i+1] != 'x' && s[i+1] != 'X')) {
      double y = pow(16, (double)i);
      double x = s[i];
      decOutput = decOutput + pow(x, y);
    }
  }
  printf("%s", decOutput);

  return decOutput;
}

void copy(char *to, char *from) {
  int i = 0;
  while((to[i] = from[i]) != '\0') {
    i++;
  }
}
lurker
  • 56,987
  • 9
  • 69
  • 103
  • 7
    Remember that output to `stdout` (which `printf` writes to) is by default *line buffered*. That means calling `printf` without any newlines will just add to a buffer. To find the *actual* location of the crash you should use a *debugger*. – Some programmer dude Jun 30 '17 at 11:15
  • 1
    On an unrelated note, you know about [`isdigit`](http://en.cppreference.com/w/c/string/byte/isdigit) but not about [`isalpha`](http://en.cppreference.com/w/c/string/byte/isalpha) or the even more apt [`isalnum`](http://en.cppreference.com/w/c/string/byte/isalnum)? – Some programmer dude Jun 30 '17 at 11:16
  • 1
    Put a line feed at the end of your print string, which should flush the output buffer: `printf("no segmentation fault after entering for loop\n");` You should see that print out then. You should have a line feed at the end of all of your debug output `printf` strings. But learning to use the debugger would be the most reliable way to locate the fault. – lurker Jun 30 '17 at 11:16
  • You should probably also learn about [`strcpy`](http://en.cppreference.com/w/c/string/byte/strcpy) and also the [`realloc`](http://en.cppreference.com/w/c/memory/realloc) function. – Some programmer dude Jun 30 '17 at 11:17
  • 1
    `s` doesn't null-terminated. Also You can use `isxdigit`. – BLUEPIXY Jun 30 '17 at 11:18
  • 1
    `for (i=0; (c=getchar()) != '\n'; i++) {}` --> `for (i=0; (c=getchar()) != '\n' && c != EOF; i++) {}` to avoid infinite loops since `getchar()` returns `EOF` in the rare event of an error. – ad absurdum Jun 30 '17 at 11:20
  • @MichaelWalz Didn't I already do that? –  Jun 30 '17 at 11:23
  • @Someprogrammerdude Got it, now back to debugging :P Thanks so much –  Jun 30 '17 at 11:25
  • @ZhengboXiang sorry, Forget my comment. But you are using `decOutput` when it is not initialized. Not sure if this is the source of the segfault – Jabberwocky Jun 30 '17 at 11:25
  • @BLUEPIXY Nice spot! Thanks! –  Jun 30 '17 at 11:25
  • @MichaelWalz Thanks, I shall find out! :P –  Jun 30 '17 at 11:26
  • Gotcha @DavidBowling Thanks I'll keep that in mind in the future –  Jun 30 '17 at 11:28
  • @Someprogrammerdude Hrm I know about isalpha's existence but I can't accept letters greater than f/F. –  Jun 30 '17 at 11:31
  • @ZhengboXiang Ah sorry, missed that! – Some programmer dude Jun 30 '17 at 15:03

1 Answers1

0

You can simply catch errors or useful warning from gcc compiler with this command.

gcc t.c -o t -l m  -Wall -Wextra 

I compiled your code and gcc produce this output.

t.c: In function ‘htoi’:
t.c:54:10: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘double’ [-Wformat=]
   printf("%s", decOutput);
          ^
t.c:19:24: warning: unused parameter ‘lim’ [-Wunused-parameter]
 int htoi(char s[], int lim) {

The correct way of print a double variable with printf is change printf("%s", decOutput); to printf("%f", decOutput); concentrate on double format specifier is %f in printf(). (read about that on true way of printing a double )

By add this change and attach simple message state that end of htoi function your code converts to:

//getchar() != EOF

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>

#define MAXLEN 100

int htoi(char *s, int lim);
void copy(char *to, char *from);

int main(void) {
  char *hexArray = (char *)malloc(MAXLEN);
  htoi(hexArray, MAXLEN);
  return 0;
}

int htoi(char s[], int lim) {
  double decOutput;
  int i = 0;
  int c;
  int size = MAXLEN;
  printf("no segmentation fault so far...");
  for (i=0; (c=getchar()) != '\n'; i++) {
    printf("no segmentation fault after entering for loop");

    if (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
      if(i >= size - 1) {
        size = size + MAXLEN;
        char *tmp = (char *)malloc(size);
        copy(tmp, s);
        free(s);
        s = tmp;
        printf("Buffer size increased to %d\n", size);
      }
      s[i] = c;
    }
    else {
      printf("INVALID INPUT!!! Decimal output may be inaccurate.");
    }
  }

  printf("exited loop");

  for(i = 0; s[i] != '\0'; i++) {
    printf("entered second for loop");
    if (s[i] != '0' || (s[i+1] != 'x' && s[i+1] != 'X')) {
      double y = pow(16, (double)i);
      double x = s[i];
      decOutput = decOutput + pow(x, y);
    }
  }

  printf("%f", decOutput);

  printf("\nend htoi\n");
  return decOutput;
}

void copy(char *to, char *from) {
  int i = 0;
  while((to[i] = from[i]) != '\0') {
    i++;
  }
}

work further on it.

EsmaeelE
  • 2,331
  • 6
  • 22
  • 31