I'm trying to make a program that writes to a file every combination of letters formed from a given phone number. I'm fairly positive it's giving the segfault where I scanf the name of the file the user wants to write to (in main) because I've put in printf tests and they don't print. For some reason, before adding in my recursive functions it doesn't give me a segfault but after adding them it does.

const char letters[8][5] = {"ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ"};

int main()
{
  int userNum[7];
  char userFile[25];
  printf("Please enter the phone number you want to process with no added 
characters or spaces: ");
  scanf("%d", &userNum);
  printf("Enter the file name (including extension and less than 25 
characters) that you would like to write to.\n");
  scanf("%s", userFile); //This is where I think the seg fault is happening
  printf("Test"); //Because this doesn't print

  FILE* file_ptr;
  char fileName[17];
  sprintf(fileName, "%s", userFile);
  file_ptr = fopen(fileName, "w");

  findWordsHelper(userNum, 7);
}

//Adding this function and the one after is what made the program start 
//giving said seg fault
void findWords(int userNum[], int digit, char words[], int n)
{
    printf("Test. n = %d", n);
    int i;
    if(digit == n)
    {
        printf("%s ", words);
        return;
    }

    for(i = 0; i < strlen(letters[userNum[digit]]); i++)
    {
        words[digit] = letters[userNum[digit]][i];
        findWords(userNum, digit+1, words, n);
        if(userNum[digit] == 0 || userNum[digit] == 1)
        {
            return;
        }
    }
}

void findWordsHelper(int userNum[], int n)
{
    printf("test");
    char result[n+1];
    result[n] = '\0';
    findWords(userNum, 0, result, n);
}

3 Answers

1
Andrew Falanga On

I'm not in an environment that I can test but I see a few things. First off, your printf test isn't printing because if has no new line character. If you're not going to put one in, call fflush. E.g

  printf("test");
  fflush(stdout);

Second, your use of scanf to read in the phone number shows a bit of misunderstanding of how scanf will treat input as an integer. You don't need an array of 7 ints for this because you've simply instructed for the input to be no extra characters. So, a phone number like 345-6789 is input as 3456789 which will be read as a single int: i.e 3 million, 4 hundred 56 thousand, 7 hundred 89. This will be read into a single integer. I know you want to treat them as separate numbers, but scanf will treat them as 1 number when not separated by whitespace. To read into a single int, this would suffice:

...
int phoneNumber;
scanf("%d", &phoneNumber);  // <--- notice the & operator

EDIT I was reading over the manual page for scanf() and when the %s specifier is used, it should insert a null-character into the string. So, the part directing to check the return and ensure a '\0' character is placed there is not applicable.


EDIT 2 I had a moment this morning and had to figure this out. I think I've got it. Something in the function findWords() looked a bit suspect and compiling, seg-faulting, and looking at the core file showed it to be the case. It's this line in that function

    for(i = 0; i < strlen(letters[userNum[digit]]); i++)

Specifically, it is the call to strlen() with the result of using userNum[] to index into letters[]. As myself, and others, have indicated, scanf() isn't going to read a "phone number" such as 3456789 (input as such) into 7 different integer values. It is read as a single int and it's going to be read into userNum[0] (and guess what? digit = 0 when the segfault occurs). This is no surprise, the letters array does not contain 3 million, 4 hundred 56 thousand, 7 hundred 89 indecies. (Assuming the number entered is what I wrote.)

As mentioned by Jasen (I think), ints don't really work well for phone numbers. At the very least, you'll have to develop a different manner of breaking apart the phone number to use as an index.

0
Community On

First of all, lack of printf output does not indicate that the program did not execute past that point, as the output is probably buffered.

You can either do fflush(stdout) immediately after a printf call, or use setvbuf with a null argument to force unbuffering.

Second, in your recursive function, each call results in calling itself up to the number of iterations in your for loop. I suspect there are logic errors there and the number of recursive calls may just explode.

Third, you definitely have a logic problem here:

int userNum[7]; ... scanf("%d", &userNum);

Looks like you are expecting that if a user enters "1234567", that each userNum[i] contains one of the digit, but that's not what's happening.

scanf would treat the argument as a pointer to an int, e.g. on a 32-bit CPU, it would put the integer value 1234567 into the first 4 bytes of "userNum". In fact, this could cause a segfault right there if the CPU cannot write to an integer (whether 16 or 32 bits) to an unaligned address. As userNum is actually an array, it may or may not be aligned suitable for an integer.

0
Jasen On
int main() {
  int userNum[7];
  char userFile[25];
  printf("Please enter the phone number you want to process with no added"
         " characters or spaces: ");

  printf("Enter the file name (including extension and less than 25 "
         " characters) that you would like to write to.\n");

  scanf("%s", userFile); //This is where I think the seg fault is happening

should be :

  scanf("%24s",userfile);

that puts a limit of 24 chars on what is read.

 char fileName[17];
 sprintf(fileName, "%s", userFile);

However userfile could be 24 long... and that can only fit 16, so it should be.

 sprintf(fileName, "%.16s", userFile);

which chops off any overflow.