Moe*_*oeb 0 c string segmentation-fault
char *s = "hello ppl.";
for (i = 0; i < strlen(s); i++) {
char c = s[i];
if (c >= 97 && c <= 122) {
c += 2;
s[i] = c;
}
}
Run Code Online (Sandbox Code Playgroud)
我想将字符串旋转两个字符: "hello ppl." -> "jgnnq rrn."
我得到了一个segmentation fault.代码有什么问题?
pax*_*blo 31
代码:
char *s = "hello ppl.";
Run Code Online (Sandbox Code Playgroud)
给你一个指向它可能只读内存的指针.那是因为C中的字符串常量是不可修改的.当您尝试写入该内存时,您很可能会遇到分段违规.标准(C99 6.4.5/6on String literals)的相关部分指出:
如果这些数组的元素具有适当的值,则这些数组是否不同是未指定的.如果程序试图修改此类数组,则行为未定义.
所以,虽然内存不具有被只读,你仍然试图通过修改它打破规则.
试试这个:
char s[] = "hello ppl.";
Run Code Online (Sandbox Code Playgroud)
这在概念上与以下相同:
char s[11]; // for the whole string plus null terminator
strcpy (s, "hello ppl.");
Run Code Online (Sandbox Code Playgroud)
换句话说,它将您想要更改的字符串放入可写内存中.以下代码:
#include <stdio.h>
#include <string.h>
int main(void) {
int i;
char s[] = "hello ppl.";
for (i = 0; i < strlen(s); i++) {
char c = s[i];
if (c >= 97 && c <= 122) {
c += 2;
s[i] = c;
}
}
printf("%s\n",s);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
"jgnnq rrn."按你的意愿给你.
还有一些我想指出哪些不是致命的事情:
97和'这样的'魔术'数字通常不是一个好主意122.使用'a'和'z'就像使用'a'和'z'一样简单,更清晰.话虽如此,我宁愿使用映射表如下:
#include <stdio.h>
#include <string.h>
int main (void) {
char *lkupPtr, *strPtr;
char str[] = "hello ppl.";
const char * const from = "abcdefghijklmnopqrstuvwzyz";
const char * const to = "cdefghijklmnopqrstuvwzyzab";
for (strPtr = str; *strPtr != '\0'; strPtr++)
if (lkupPtr = strchr (from, *strPtr)) != NULL)
*strPtr = to[(int)(lkupPtr - from)];
printf("%s\n",str);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这样可以解决我上面提到的所有问题,如果您处于国际化环境(而不仅仅是纯ASCII或EDCDIC),您可以根据需要添加更多映射.
在我看来,这应该足够快,除了最苛刻的要求之外的所有要求(我的PC上每秒钟超过300万个字符).如果您对性能的需求几乎无法满足,但又不想选择针对特定CPU的手工组装,您可以尝试以下方法.
它仍然完全符合C标准,但由于所有繁重的计算工作在开始时完成,因此可以提供更好的性能.它创建一个包含所有可能字符值的表,对其进行初始化,以便默认情况下每个字符都转换为自身,然后更改您感兴趣的特定字符.
这将删除翻译本身对字符的任何检查.
#include <stdio.h>
#include <string.h>
#include <limits.h>
static char table[CHAR_MAX + 1];
static void xlatInit (void) {
int i;
char * from = "abcdefghijklmnopqrstuvwzyz";
char * to = "cdefghijklmnopqrstuvwzyzab";
for (i = 0; i <= CHAR_MAX; i++) table[i] = i;
while (*from != '\0') table[*from++] = *to++;
}
int main (void) {
char *strPtr;
char str[] = "hello ppl.";
xlatInit(); // Do this once only, amortize the cost.
for (strPtr = str; *strPtr != '\0'; strPtr++)
*strPtr = table[*strPtr];
printf("%s\n",str);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
变量s指向只读存储器.这意味着它无法修改.你会想要使用:
char varname[] = "...";
Run Code Online (Sandbox Code Playgroud)
需要注意:
char varname[] = "...";
Run Code Online (Sandbox Code Playgroud)
将数据放在堆栈中.确保您没有返回指向函数本地数据的指针.如果是这种情况,您将需要查看malloc以在堆中分配内存.
另一个问题:
for (i = 0; i < strlen(s); i++) {...} is O(N^2)
Run Code Online (Sandbox Code Playgroud)
原因是strlen(s)是每次循环时都执行的O(N)操作.改进将是:
int len = strlen(s);
for(i=0;i<len;i++) { ... }
Run Code Online (Sandbox Code Playgroud)
这样我们只进行一次strlen(s)计算并重用结果.
在char *s = "hello ppl."你没有分配任何内存,而是指向一个可能驻留在程序的只读内存中的字符串.理想情况下应该是const char*.现在,如果您尝试修改它,它将崩溃.
代码:
char *s = "hello ppl.";
Run Code Online (Sandbox Code Playgroud)
在字符串表中创建一个条目,通常在代码段(程序的只读空间)中.任何尝试更改它都会通过尝试修改只读内存来导致段错误.创建/初始化要修改的字符串的适当方法是:
char s[] = "hello ppl.";
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
535 次 |
| 最近记录: |