Search code examples
cfunctionsegmentation-faultprogram-entry-pointmorse-code

C function for converting text to morse code


I'm trying to write a program where the morse code of the given text by the system is required. About the converting text to morse code, I wrote them all in main (separately from the program file itself). And now, my aim is to write it as a function in order to use it in the other functions of the program. Whenever I try, it gives a segmentation fault. Can anyone help me to construct the function itself from scratch?

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdint.h>
#include<ctype.h>
#include <time.h>

char * fileName1 = NULL;
char * fileName2 = NULL;

int main(int argc, char * argv[]) {
  int n;
  for (n = 0; n < argc; n++) {
    // printf("Argument %s\n",argv[n]); // prints options  delete this in the end,just for debugging
    if (strcmp(argv[n], "-text") == 0) {
      //text to morsecode
      int c, v = 0;
      char * str = (char * ) malloc(v);
      str = (char * ) realloc(str, (c + strlen(argv[n + 1])));
      strcat(str, argv[n + 1]);
      strcat(str, " ");

      char *alphamorse[]={".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
      char *nummorse[]={"-----",".----","..---","...--","....-",".....","-....","--...","---..","----."};

      int i;
      char str1[1000];
      i = 0;
      while (str[i] != '\0') {
        if (str[i] != ' ' && (!isdigit(str[i]))) {
          printf("%s ", alphamorse[toupper(str[i]) - 65]);
        }
        if (str[i] == ' ') {
          printf(" ");
        }
        if (isdigit(str[i]) && str[i] != ' ') {
          printf("%s ", nummorse[str[i] - 48]);
        }
        i++;
      }
      printf("\n");
      // end of text to morsecode
    }
    if (strcmp(argv[n], "-o") == 0) {
      //output = concat(output, argv[n + 1]);
      n++;
      continue;
    }
    if (strcmp(argv[n], "--") == 0) {
      if (n + 1 <= argc) {
        fileName1 = argv[++n];
        printf("    fileName1=%s\n", fileName1);
      }
      if (n + 1 <= argc) {
        fileName2 = argv[++n];
        printf("    fileName2=%s\n", fileName2);
      }
    }
  }
  return 0;
}

Solution

  • I don't know if this is the bug that's causing an issue, but it is a bug:

    int c, v = 0;
    char *str = (char *)malloc(v);
        str = (char *)realloc(str, (c + strlen(argv[n+1])));
    

    First, c is uninitialized. It could be any value, including a negative value. Hence, undefined behavior in your program.

    Also, that malloc followed by a a realloc call isn't needed. Just allocate once and be done with it.

    I think this is what you intended to do

    size_t len = strlen(argv[n+1]);
    str = (char*)malloc(len + 1 + 1); // +1 for space char to be appended, +1 again for null char
    strcpy(str, argv[n+1]); // copy string
    strcat(str, " ");       // append a space
    

    But there's an even simpler solution. You don't even need to copy argv[n+1] into str. Just declare str as a pointer and reference argv[n+1] directly.

    const char* str = argv[n+1];
    

    Now str and argv[n+1] reference the same string. And str is valid for the entirety of the program. The rest of your program remains the same.

    This looks suspicious:

      i = 0;
      while (str[i] != '\0') {
        if (str[i] != ' ' && (!isdigit(str[i]))) {
          printf("%s ", alphamorse[toupper(str[i]) - 65]);
        }
        if (str[i] == ' ') {
          printf(" ");
        }
        if (isdigit(str[i]) && str[i] != ' ') {
          printf("%s ", nummorse[str[i] - 48]);
        }
        i++;
      }
    

    You are redundantly calling isdigit and evaluating to make sure str[i] is not a space. No point in checking if its a space if you already know it's a digit. Either it's a digit, a letter, or something that can't be converted. Your code will errneously treat puncutation marks as values to lookup in alphamorse. The following will skip over punctuation marks and just treat those characters as spaces.

      i = 0;
      while (str[i] != '\0') {
    
        if ((str[i] >= 'A' && str[i] <= 'Z') || (str[i] >= 'a' && str[i] <= 'z')) {
          printf("%s ", alphamorse[toupper(str[i]) - 'A']);
        }
        else if (isdigit(str[i])) {
          printf("%s ", nummorse[str[i] - '0']);
        }
        else {
            printf(" ");
        }
        i++;
      }
    

    Everything after that, I don't know what it's for. General advice is that you parse the arguments from argv[] first. Then do the text conversion outside of the loop that iterates over the command line arguments. Then do your save to file code.