• 关于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] != '');
     7 
     8   begin = *stringp;
     9   if (begin != NULL)
    10     {
    11       char *end = begin;
    12 
    13       while (*end != '' || (end = NULL))
    14     {
    15       const char *dp = delim;
    16 
    17       do
    18         if (*dp == *end)
    19           break;
    20       while (*++dp != '');
    21 
    22       if (*dp != '')
    23         {
    24           *end++ = '';
    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++ = '';
    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的指向从堆区换到了只读存储区,所以会出现错误。这个错误很容易发现,但是在编码的过程中不注意还是很容易犯的,可能是我自身的问题,以作记录,以谨记。

     

     

  • 相关阅读:
    HDU 5791 Two (DP)
    POJ 1088 滑雪 (DPor记忆化搜索)
    LightOJ 1011
    POJ 1787 Charlie's Change (多重背包 带结果组成)
    HDU 5550 Game Rooms (ccpc2015 K)(dp)
    HDU 5542 The Battle of Chibi (ccpc 南阳 C)(DP 树状数组 离散化)
    HDU 5543 Pick The Sticks (01背包)
    HDU 5546 Ancient Go (ccpc2015南阳G)
    NB-IoT的DRX、eDRX、PSM三个模式 (转载,描述的简单易懂)
    MQTT 嵌入式端通讯协议解析(转)
  • 原文地址:https://www.cnblogs.com/coolYuan/p/14373174.html
Copyright © 2020-2023  润新知