我找不到导致间歇性崩溃的指针错误。你是否可以?

I can't find the pointer error that's causing an intermittent crash. Can you?

这在大多数情况下都有效,但我偶尔会崩溃。某处存在指针问题,但我还看不到它。

代码从字符串中取出单词,并构建它们的链表。单词必须包括相邻的标点符号,但不能有空格。例如,字符串:

He said, 'blah blah!' and then died.

会变成字符串

He

said,

'blah

blah!'

and

then

died.

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

unsigned longestword(char *str);

typedef struct _list{
    char *p;
    struct _list *next;
}list;


int main(void){
    char str[]="   'Well!' thought Alice to herself, 'after such a fall as this, I shall think nothing of tumbling down stairs!'";
    unsigned k, i=0, l, j, wordscout;
    list *curr, *root=NULL;

    k =longestword(str);
    puts(str);
    printf("\nlongest word in string is %u letters long.", k);

    do{
        //  skip over any leading whitespace.
        for(; str[i] && isspace(str[i]); i++);
        if(!str[i]) break;

        //  count length of word that begins with str[i].
        for(wordscout=i, l=0; str[wordscout] && !isspace(str[wordscout]); wordscout++, l++);

        //  if this is first word, malloc space to root.
        if(root==NULL){
            if((root = malloc(sizeof(list))) == NULL){
                printf("\nmalloc() failed.");
                exit(1);
            }
            curr = root;
        }

        //  if not first word, malloc space to curr->next.
        else{
            if((curr->next = malloc(sizeof(list))) == NULL){
                printf("\nmalloc() failed.");
                exit(1);
            }
            curr = curr->next;
        }

        //  malloc space in current struct for string.
        if((curr->p = malloc(1+l*sizeof(char))) == NULL){
            printf("\nmalloc() failed.");
            exit(1);
        }

        //  read first word into new space.
        j=0;
        while(!isspace(str[i])) curr->p[j++] = str[i++];
        curr->p[j] = '[=10=]';

        //  check if word is there.
        printf("\n<<%s>>", curr->p);
    }while(str[wordscout]);
}


//  takes a null-terminated string, returns length of longest word in the string. word includes adjacent punctuation, but not whitespace.
unsigned longestword(char *str){

    //  check that word is null-terminated before carrying on.
    unsigned j,k,i,l;
    l = strlen(str);
    for(i=j=k=0; i<=l; i++){
        if(isalpha(str[i]) || ispunct(str[i])) j++;
        else if(j>k){ k=j; j=0; }
        else j=0;
    }
    return k;
}

longestword()函数可以忽略。它有效,稍后用于其他用途。

我的输出如下,这就是我想要的。但是时不时地,它会在显示以下内容后崩溃:

   'Well!' thought Alice to herself, 'after such a fall as this, I shall think n
othing of tumbling down stairs!'

longest word in string is 8 letters long.
<<'Well!'>>
<<thought>>
<<Alice>>
<<to>>
<<herself,>>
<<'after>>
<<such>>
<<a>>
<<fall>>
<<as>>
<<this,>>
<<I>>
<<shall>>
<<think>>
<<nothing>>
<<of>>
<<tumbling>>
<<down>>
<<stairs!'>>
Process returned 0 (0x0)   execution time : 0.062 s
Press any key to continue.
如果字符串不以空格结尾,

while(!isspace(str[i])) 将永远不会终止。

段错误可能取决于在字符串末尾后空格在垃圾中出现之前需要多长时间。

相反,您可以 while( i < wordscout )。请注意,l 是多余的,您应该使用 wordscout - i.

你应该在某处将 curr->next 设置为 NULL。

curr->next = malloc() 是不够的,因为 malloc() 不会将 next 初始化为 NULL 指针。您列表中的 last 条目将 curr->next 指向一个随机位置。一旦你去那个地方你的程序就会崩溃。

如果你不明白上面的内容,这里是如何证明的:

将以下函数添加到您的程序中:

void foo()
{
    /* Fill the heap with garbage */
    list ** p = malloc(sizeof(list*)*8192);
    int i;
    for(i=0;i<8192;++i)
    {
       p[i]=malloc(sizeof(list));
       p[i]->next=p[i]; /*just something*/
    }
    for(i=0;i<8192;++i)
    {
       free( p[i] );
    }
    free(p);
}

运行 在填写列表之前:

int main(void){
    foo(); <<-- my new line
    char str[]="......

打印最后一个下指针:

    }while(str[wordscout]);

    printf("%p\n", curr->next); <<--my new line

    return 0;

这是打印出来的内容:

...
<<tumbling>>
<<down>>
<<stairs!'>>0x1f61240 <<-- non-null here!

这意味着当您浏览列表时,您没有正确的结束标记。使用您的列表的任何人都不知道他们何时到达最后一个元素。

最好的修复位置是在设置 curr->p 之后设置 curr->next:

//  malloc space in current struct for string.
if((curr->p = malloc(1+l*sizeof(char))) == NULL){
    printf("\nmalloc() failed.");
    exit(1);
}

// At this moment curr->next should be NULL
curr->next=NULL;