今天在调用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的指向从堆区换到了只读存储区,所以会出现错误。这个错误很容易发现,但是在编码的过程中不注意还是很容易犯的,可能是我自身的问题,以作记录,以谨记。