由C中的fgets()引起的分段错误

由C中的fgets()引起的分段错误,c,segmentation-fault,fgets,C,Segmentation Fault,Fgets,这是一个我不理解的问题-我主要使用的是fgets(),它可以工作。我(我认为)在函数中使用它的方式完全相同,我得到一个错误[分段错误核心转储--退出代码139] 这段代码是基于Ivor Horton的《开始C》(这是一个老版本,但我只是想从中学习基础知识)一书中的一个示例程序编写的 我的程序如下所示。我正在使用Geany处理*nix(基本上是用GCC编译)。您可以看到,fgets在main中工作(输出是您输入的字符串)。但它在函数stru in()中不工作。它一直到第二个printf()语句输入

这是一个我不理解的问题-我主要使用的是
fgets()
,它可以工作。我(我认为)在函数中使用它的方式完全相同,我得到一个错误[分段错误核心转储--退出代码139]

这段代码是基于Ivor Horton的《开始C》(这是一个老版本,但我只是想从中学习基础知识)一书中的一个示例程序编写的

我的程序如下所示。我正在使用Geany处理*nix(基本上是用GCC编译)。您可以看到,
fgets
在main中工作(输出是您输入的字符串)。但它在函数
stru in()
中不工作。它一直到第二个
printf()
语句输入字符串,无需进一步。请注意,在本书中,Horton使用了
get()
。我试图在这里实现一个更安全的字符串输入函数,但没有乐趣

顺便说一下,程序应该对存储在字符串指针数组中的字符串进行排序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TRUE 1
#define FALSE 0
#define MAX_NUM_STRINGS 50


int str_in(char **);              /*Pointer to a string pointer*/
void str_sort(char *[], int n);   /*Array of pointers to strings, number of strings in array*/
void str_out (char *[], int n);   /*Array of pointers to strings, number of strings in array*/


int main(){

    char *pS[MAX_NUM_STRINGS] = { NULL };                  /*Array of pointers to strings stored in str_space*/
    int numStrings = 0;                                     /*Count of strings*/
    char buffer[BUFSIZ];

    printf("Enter a string\n");
    fgets(buffer, BUFSIZ, stdin);
    printf("%s", buffer);
    printf("fgets works here\n\n");


    /* get string input from user - a pointer to each string is saved in pS */
    while ( str_in(&pS[numStrings]) && numStrings < MAX_NUM_STRINGS)
        numStrings++;
    if ( numStrings > 0 ){
        str_sort(pS, numStrings);
        str_out(pS, numStrings);
    }

    return 0;
}


    int str_in(char** pString){

        char buffer[BUFSIZ];
        char *p;

        printf ("Enter string:\n");

        fgets(buffer, 60, stdin);
        printf("fgets doesn't work here!!\n");

        if( buffer != NULL ){
            printf("here");
            if ((p = strchr(buffer, '\n')) != NULL)
                *p = '\0';                                  /*replace newline with null character*/
            else
                return FALSE;
            if ( strlen(buffer) > 0 ){
                strcpy(*pString, buffer);
                return TRUE;
            }
            else
                return FALSE;                               /*blank line - end of input*/
        }
        else
            return FALSE;

    }


    void str_sort(char* pStrings[], int n){
    /*sort strings by manipulating array of string pointers*/

        char *temp;
        int sorted = FALSE;
        int i = 0;

        while (!sorted){

            sorted = TRUE;
            for(i = 0; i < n - 1; i++){
                temp = pStrings[i];
                if ( strcmp(temp, pStrings[i+1]) > 1 ){
                    pStrings[i] = pStrings[i+1];
                    pStrings[i+1] = temp;
                    sorted = FALSE;
                    break;
                }
            }

        }

    }


    void str_out(char* pStrings[], int n){
    /*print strings to standard output.  Free memory as each string is printed */

        int i = 0;

        printf("Sorted strings:\n");
        for(i = 0; i < n; i++){
            printf("%s", pStrings[i]);
            free(pStrings[i]);
        }

    }
#包括
#包括
#包括
#定义真1
#定义FALSE 0
#定义最大数量字符串50
int str_in(char**);/*指向字符串指针的指针*/
void str_sort(char*[],int n);/*指向字符串的指针数组,数组中的字符串数*/
void str_out(char*[],int n);/*指向字符串的指针数组,数组中的字符串数*/
int main(){
char*pS[MAX_NUM_STRINGS]={NULL};/*指向存储在str_空间中的字符串的指针数组*/
int numStrings=0;/*字符串计数*/
字符缓冲区[BUFSIZ];
printf(“输入字符串”);
fgets(缓冲区、BUFSIZ、标准输入);
printf(“%s”,缓冲区);
printf(“fgets在此工作\n\n”);
/*从用户获取字符串输入-指向每个字符串的指针保存在pS中*/
while(str_in(&pS[numStrings])&&numStrings0){
str_排序(pS,numstring);
stru_out(pS,numStrings);
}
返回0;
}
int str_in(字符**pString){
字符缓冲区[BUFSIZ];
char*p;
printf(“输入字符串:\n”);
fgets(缓冲器,60,标准输入);
printf(“fgets在这里不起作用!!\n”);
if(缓冲区!=NULL){
printf(“此处”);
if((p=strchr(缓冲区,'\n'))!=NULL)
*p='\0';/*用空字符替换换行符*/
其他的
返回FALSE;
如果(strlen(缓冲区)>0){
strcpy(*pString,buffer);
返回TRUE;
}
其他的
返回FALSE;/*空行-输入结束*/
}
其他的
返回FALSE;
}
void str_排序(char*pStrings[],int n){
/*通过操纵字符串指针数组对字符串进行排序*/
字符*温度;
int=FALSE;
int i=0;
而(!排序){
排序=真;
对于(i=0;i1){
pStrings[i]=pStrings[i+1];
pStrings[i+1]=温度;
排序=假;
打破
}
}
}
}
void stru_out(char*pStrings[],int n){
/*将字符串打印到标准输出。打印每个字符串时释放内存*/
int i=0;
printf(“排序字符串:\n”);
对于(i=0;i
您必须检查fgets的返回值,以查看是否已成功接收到某些内容,如果未成功接收,则不应将缓冲区作为字符串使用,因为您不会NUL终止缓冲区

/* Checking for buffer != NULL is of no use */
/* as buffer will always be not NULL since */
/* since you have allocated it as char buffer[BUFSIZ] */

if (fgets(buffer, BUFSIZ, stdin) == NULL) {
   /* buffer may not be a valid string */
}
因此,您可以在输入函数时(在声明完成后)立即将缓冲区初始化为NUL字符串

buffer[0] = 0; /* initialize to NUL string */
现在,您可以在任何地方将缓冲区用作字符串


还要注意的是,如果BUFSIZ太大,大于几KB,则可能由于堆栈溢出而导致seg错误。如果它们太大,则可以将缓冲区设置为“静态字符”而不是“字符”。

分段错误不是由
fgets()
引起的,而是由
strcpy()
引起的:

您试图写入
*pString
,但从未为其分配内存。
main()
中的
pS
只是一个空指针数组

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TRUE 1
#define FALSE 0
#define MAX_NUM_STRINGS 50


int str_in(char **);              /*Pointer to a string pointer*/
void str_sort(char *[], int n);   /*Array of pointers to strings, number of strings in array*/
void str_out (char *[], int n);   /*Array of pointers to strings, number of strings in array*/


int main(){

    char *pS[MAX_NUM_STRINGS] = { NULL };                  /*Array of pointers to strings stored in str_space*/
    int numStrings = 0;                                     /*Count of strings*/
    char buffer[BUFSIZ];

    printf("Enter a string\n");
    fgets(buffer, BUFSIZ, stdin);
    printf("%s", buffer);
    printf("fgets works here\n\n");


    /* get string input from user - a pointer to each string is saved in pS */
    while ( str_in(&pS[numStrings]) && numStrings < MAX_NUM_STRINGS)
        numStrings++;
    if ( numStrings > 0 ){
        str_sort(pS, numStrings);
        str_out(pS, numStrings);
    }

    return 0;
}


    int str_in(char** pString){

        char buffer[BUFSIZ];
        char *p;

        printf ("Enter string:\n");

        fgets(buffer, 60, stdin);
        printf("fgets doesn't work here!!\n");

        if( buffer != NULL ){
            printf("here");
            if ((p = strchr(buffer, '\n')) != NULL)
                *p = '\0';                                  /*replace newline with null character*/
            else
                return FALSE;
            if ( strlen(buffer) > 0 ){
                strcpy(*pString, buffer);
                return TRUE;
            }
            else
                return FALSE;                               /*blank line - end of input*/
        }
        else
            return FALSE;

    }


    void str_sort(char* pStrings[], int n){
    /*sort strings by manipulating array of string pointers*/

        char *temp;
        int sorted = FALSE;
        int i = 0;

        while (!sorted){

            sorted = TRUE;
            for(i = 0; i < n - 1; i++){
                temp = pStrings[i];
                if ( strcmp(temp, pStrings[i+1]) > 1 ){
                    pStrings[i] = pStrings[i+1];
                    pStrings[i+1] = temp;
                    sorted = FALSE;
                    break;
                }
            }

        }

    }


    void str_out(char* pStrings[], int n){
    /*print strings to standard output.  Free memory as each string is printed */

        int i = 0;

        printf("Sorted strings:\n");
        for(i = 0; i < n; i++){
            printf("%s", pStrings[i]);
            free(pStrings[i]);
        }

    }

另一件事是使用
if(buffer!=NULL)进行测试
,这永远不会是真的,因为
缓冲区是一个数组,而不是指针。

我遗漏了什么吗?我没有看到任何字符串的空间被分配。另外:在
中,stru in
缓冲区不可能是空的…我认为只有在发生某种非常不寻常的输入错误的情况下,它才会是空的-下面的例子是lowing在这里:@topsail:
buffer
是一个数组对象,而不是指针;它衰减为指向其第一个元素的指针,该元素永远不能为null。好的。现在这不是必需的,但看看Sundar下面的注释,如果fgets()返回null,那么null指针不会存储在我的变量缓冲区中吗(即使它没有改变数组中的任何内容)。谢谢。就是这样。事实上,在霍顿的例子中,我漏掉了一行:
*pString=(char*)malloc(strlen(buffer)+1);
我有点明白你的意思,但是fgets()在输入中附加一个空字符?因此,只要它没有完全无法从用户处获取输入,它至少应该是一个空字符(可能是一个换行符,后跟一个空字符。根据C标准(第7.19.7.2节)“如果遇到文件结尾,且数组中未读取任何字符,则数组的内容保持不变,并返回空指针”。当返回值为空时,FGET无需追加NUL。