关于strsep函数以及联想

今天在调用strsep函数时,报了Segmentation fault错误,strsep函数原型如下:

char *strsep(char **stringp, const char *delim);

第一个参数是个二级指针,而且没有const修饰,我猜测在man手册中只要是添加const修饰的参数都是只读的(当然这是肯定的),而那些没有添加const修饰的一般为可读可写的。

根据这种猜测,再根据调用strsep时。传递的第一个参数是一个const char *,这时程序运行时就回报Segmentation fault错误。

例:

 1 #include <stdio.h>
 2 
 3 int main(void)
 4 {
 5     char *buf = "123456,123456";
 6 
 7     strsep(&buf, ",");
 8 
 9     return 0;
10 }

编译运行结果:

# ./a.out 
Segmentation fault

修改如下:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 int main(void)
 6 {
 7     char *buf = malloc(32);
 8 
 9     memcpy(buf, "123456,123456", sizeof("123456,123456"));
10 
11     strsep(&buf, ",");
12 
13     return 0;
14 }

另一种修改方式:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 int main(void)
 6 {
 7     char buf[32] = {0};
 8     
 9     memcpy(buf, "123456,123456", sizeof("123456,123456"));
10 
11     strsep(&buf, ",");
12 
13     return 0;
14 }

上边这种修改在编译的时候会有一个警告:

4.c: In function ‘main’:
4.c:13:5: warning: passing argument 1 of ‘strsep’ from incompatible pointer type [enabled by default]
     strsep(&buf, ",");
     ^
In file included from 4.c:3:0:
/usr/include/string.h:555:14: note: expected ‘char ** __restrict__’ but argument is of type ‘char (*)[32]’
 extern char *strsep (char **__restrict __stringp,
              ^

可以将strsep(&buf, ",");修改为strsep((char **)(&buf), ",");以消除影响。但是这个并不是导致问题的所在。

上边的修改并没有解决问题。

再次修改:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 int main(void)
 6 {
 7     char buf[32] = {0};
 8     char *tmp = NULL;
 9     
10     memcpy(buf, "123456,123456", sizeof("123456,123456"));
11 
12     tmp = buf;
13     strsep(&tmp, ",");
14 
15     return 0;
16 }

以上两种方式都可以解决所遇到的问题。

这是什么原因的导致的呢!以下是从glibc中找到的源码:

 

 1 char *
 2 __strsep (char **stringp, const char *delim)
 3 {
 4   char *begin;
 5 
 6   assert (delim[0] != '\0');
 7 
 8   begin = *stringp;
 9   if (begin != NULL)
10     {
11       char *end = begin;
12 
13       while (*end != '\0' || (end = NULL))
14     {
15       const char *dp = delim;
16 
17       do
18         if (*dp == *end)
19           break;
20       while (*++dp != '\0');
21 
22       if (*dp != '\0')
23         {
24           *end++ = '\0';
25           break;
26         }
27 
28       ++end;
29     }
30 
31       *stringp = end;
32     }
33 
34   return begin;
35 }
 1 char *
 2 __strsep (char **stringp, const char *delim)
 3 {
 4   char *begin, *end;
 5 
 6   begin = *stringp;
 7   if (begin == NULL)
 8     return NULL;
 9 
10   /* Find the end of the token.  */
11   end = begin + strcspn (begin, delim);
12 
13   if (*end)
14     {
15       /* Terminate the token and set *STRINGP past NUL character.  */
16       *end++ = '\0';
17       *stringp = end;
18     }
19   else
20     /* No more delimiters; this is the last token.  */
21     *stringp = NULL;
22 
23   return begin;
24 }

以上是在glic中找到的俩种实现方法,这两种方式都对stringp中的数据进行了修改,所以才会出现上述错误。

在解决问题的过程中,还遇见一个问题:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 
 5 int main(void)
 6 {
 7     char *buf = malloc(32);
 8     
 9     buf = "123456,123456";
10 
11     memcpy(buf, "123456,123456", sizeof("123456,123456"));
12 
13     strsep(&buf, ",");
14 
15     return 0;
16 }

上边这段代码在运行的时候也会报Segmentation fault错误,这其实是因为buf的指向从堆区换到了只读存储区,所以会出现错误。这个错误很容易发现,但是在编码的过程中不注意还是很容易犯的,可能是我自身的问题,以作记录,以谨记。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章