尝试扫描字符串时如何解决分段错误?

时间:2019-05-02 01:35:13

标签: c string segmentation-fault scanf

我正在尝试编写一个程序,将给定电话号码形成的字母的每个组合写入文件。我相当肯定,它会给segfault扫描用户要写入的文件名(主要是在其中),因为我已经进行了printf测试,但无法打印。由于某种原因,在添加递归函数之前,它不会给我一个段错误,但是在添加它们之后,它确实可以。

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 个答案:

答案 0 :(得分:1)

我不在可以测试的环境中,但是我看到了一些东西。首先,您的printf测试不会打印,因为如果没有换行符。如果您不打算放入,请致电fflush。例如

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

第二,您使用scanf来读取电话号码显示了一些关于scanf如何将输入视为整数的误解。为此,您不需要7个整数的数组,因为您只是指示输入不要包含多余的字符。因此,将像345-6789这样的电话号码输入为3456789,该电话号码将被读取为一个整数:即3,000,000、4,55.6万,7,900,89。这将被读取为一个整数。我知道您想将它们视为单独的数字,但是scanf在不使用空格分隔时会将其视为1的数字。要读入单个int,就足够了:

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

编辑 我正在阅读scanf()的手册页,当使用%s说明符时,它应该在字符串中插入一个空字符。因此,指示检查退货并确保在其中放置'\0'字符的部分不适用。


编辑2 我今天早上有一刻,不得不弄清楚这一点。我想我明白了。函数findWords()中的某些内容看起来有些可疑,并且进行了编译,段错误,并且查看核心文件表明情况确实如此。该功能就是这一行

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

具体地说,它是对strlen()的调用,其结果是使用userNum[]索引到letters[]中。正如我自己和其他人所指出的那样,scanf()不会将“ 3456789”之类的“电话号码”读取为7个不同的整数值。它被读取为单个int,并将被读取到userNum[0]中(发生段错误时,您猜怎么着?digit = 0)。毫不奇怪,letters数组不包含 300万,400 56000、700 89指数。 (假设输入的号码是我写的。)

正如Jasen(我认为)所提到的,int对于电话号码并不是很有效。至少,您必须开发出一种不同的方式来分解电话号码以用作索引。

答案 1 :(得分:0)

首先,缺少printf输出并不表示该程序未在该点之后执行,因为输出可能已被缓冲。

您可以在printf调用后立即执行fflush(stdout),也可以将setvbuf与null参数一起使用来强制取消缓冲。

第二,在递归函数中,每次调用都会导致自身调用,直到您的for循环中的迭代次数为止。我怀疑那里存在逻辑错误,并且递归调用的数量可能会激增。

第三,您在这里肯定有一个逻辑问题:

  

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

看起来您期望如果用户输入“ 1234567”,则每个userNum [i]都包含一个数字,但这不是正在发生的情况。

scanf会将参数视为指向int的指针,例如在32位CPU上,它将整数值1234567放入“ userNum”的前4个字节中。实际上,如果CPU无法将整数(无论是16位还是32位)写入未对齐的地址,则此可能会在此处引起段错误。由于userNum实际上是一个数组,因此它可能适合也可能不适合整数。

答案 2 :(得分:0)

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

应该是:

  scanf("%24s",userfile);

读取的字符数不得超过24个字符。

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

但是userfile可以是24个长...并且只能容纳16个,所以应该是。

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

可消除任何溢出。