这在大多数情况下都有效,但我偶尔会崩溃。有一个指针的问题,但我还看不出来。
代码从字符串中取出单词,并构建它们的链表。单词必须包含相邻的标点符号,但不能有空格。例如,字符串
他说:"废话!’然后就死了。
会变成字符串
他,
'等等
废话!'
和
然后死了。
#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] = ' ';
// 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->旁边为NULL。
curr->next = malloc()
是不够的,因为malloc()不会将next
初始化为NULL指针。列表中的最后一个条目将使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[]="......
打印最后一个next指针:
}while(str[wordscout]);
printf("%pn", curr->next); <<--my new line
return 0;
打印结果如下:
...
<<tumbling>>
<<down>>
<<stairs!'>>0x1f61240 <<-- non-null here!
这意味着当你导航你的列表时,你没有适当的结束标记。无论谁在使用你的列表,都不知道他们什么时候到达了最后一个元素。
最好在设置curr->p:
之后设置curr->// 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;