字符串操作导致段错误 C
String operations cause segfault C
我正在尝试 'deep copy' 一个字符串,以便我可以对一个副本执行操作,同时保留原始副本。这是我得到的基本示例,由于某种原因,strncpy 调用会导致段错误。请帮忙
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char* stringA = "someVeryinTeresTingString";
char* stringB = malloc(sizeof(char) * strlen(stringA));
printf("A: %s, B: %s\n", stringA, stringB);
for (int i = 0; i < strlen(stringA); i++) {
stringB[i] = tolower(stringA[i]);
}
printf("A: %s, B: %s\n", stringA, stringB);
strncpy(stringA, stringB, strlen(stringA) - 1);
printf("A: %s, B: %s\n", stringA, stringB);
}
最简单的解决方法是制作该字符串文字的本地副本:
char stringA[] = "someVeryinTeresTingString";
其他一切都一样。
请注意,在原始代码中,您有一个指向不可变内存的指针,而在这个版本中,您有一个本地(堆栈)数组,该数组使用该字符串的副本进行初始化。
另一件需要注意的事情是,如果您要复制和操作 C 字符串,请执行以下操作:
char* stringB = strdup(stringA);
for (int i = 0; i < strlen(stringB); ++i) {
stringB[i] = tolower(stringB[i]);
}
或者更有效地避免所有这些昂贵的 strlen()
调用:
char* stringB = strdup(stringA);
for (char* p = stringB; *p; ++p) {
*p = tolower(*p);
}
这一行:
char* stringB = malloc(sizeof(char) * strlen(stringA));
应该是这样的:
char* stringB = malloc(sizeof(char) * (strlen(stringA) + 1));
那么你就可以复制stringA末尾的\0了
此外,您想要复制到文字字符串 - 即分段错误
char *strncpy(char *dest, const char *src, size_t n)
我会尝试在您自己的代码中评论并更正我看到的错误:
(我不会更正那些可以消除或以其他方式更好地完成的事情,但它们是正确的或无害的,所以你只会看到 必须 更正的内容,因为编程错误,而不是关于风格或编程用途的问题)
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char* stringA = "someVeryinTeresTingString";
/* you need to consider the space for the final null character in the malloc() call */
char* stringB = malloc(sizeof(char) * (strlen(stringA) + 1));
/* you don't need to use sizeof(char) as it is always equal to one.
* Multiplying by one is not necessary, but you'll probably know.
* char is warranteed by C standard that its sizeof is one. */
/* you need to copy the string *before* printing, or you will print an
* uninitialized string. Or at least initialize stringB to zeros, so you can
* use it with printf like functions (I do initialize the first char position to
* zero to make it appear as a length zero "" string)
* You will incurr in undefined behaviour if you don't do this. */
stringB[0] = '[=10=]';
printf("A: %s, B: %s\n", stringA, stringB);
/* you need to copy the strings, so you can do it better if you test when
* stringA[i] == '[=10=]', so you don't calculate the length of a string that is
* not going to change at every loop iteration. I will not change your
* code, because this is not an error. But strlen() searches from the
* beginning of the string for the '[=10=]' char, character by character,
* and this test is done at every loop iteration. With the expression
* stringA[i] == 0 you do only a test per loop iteration to see if
* the char at position i in stringA is the null character. */
int i;
for (i = 0; i < strlen(stringA); i++) {
stringB[i] = tolower(stringA[i]);
}
/* you have not copied the final '[=10=]', so I do it now. I need to move the
* declaration of i outside of the loop to be able to use it's value. */
stringB[i] = 0; /* you can use 0 or '[=10=]' interchangeably */
printf("A: %s, B: %s\n", stringA, stringB);
/* nope. you need to copy the strings with a normal strcpy() as you know that
* both are the same length (better, you know that the space in stringB
* is the same as the length of stringA plus one). If you do this, you will not copy the last '[=10=]' char, so wee need to append it.
* well, I don't know if that is what you want, so I don't actually touch anything here. */
strncpy(stringA, stringB, strlen(stringA) - 1);
/* stringB should be one char shorter than stringA */
printf("A: %s, B: %s\n", stringA, stringB);
}
顺便提一下,建议您使用 strdup(3)
。这是个好主意,在这种情况下您不需要考虑最终的空值,因为 strdup()
会处理它。请记住,strdup(3)
并未包含在许多 C 标准修订版中,因此如果您这样做,您可能会遇到麻烦
把你的程序移到一个没有它的地方(无论如何,这应该很奇怪)
我正在尝试 'deep copy' 一个字符串,以便我可以对一个副本执行操作,同时保留原始副本。这是我得到的基本示例,由于某种原因,strncpy 调用会导致段错误。请帮忙
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char* stringA = "someVeryinTeresTingString";
char* stringB = malloc(sizeof(char) * strlen(stringA));
printf("A: %s, B: %s\n", stringA, stringB);
for (int i = 0; i < strlen(stringA); i++) {
stringB[i] = tolower(stringA[i]);
}
printf("A: %s, B: %s\n", stringA, stringB);
strncpy(stringA, stringB, strlen(stringA) - 1);
printf("A: %s, B: %s\n", stringA, stringB);
}
最简单的解决方法是制作该字符串文字的本地副本:
char stringA[] = "someVeryinTeresTingString";
其他一切都一样。
请注意,在原始代码中,您有一个指向不可变内存的指针,而在这个版本中,您有一个本地(堆栈)数组,该数组使用该字符串的副本进行初始化。
另一件需要注意的事情是,如果您要复制和操作 C 字符串,请执行以下操作:
char* stringB = strdup(stringA);
for (int i = 0; i < strlen(stringB); ++i) {
stringB[i] = tolower(stringB[i]);
}
或者更有效地避免所有这些昂贵的 strlen()
调用:
char* stringB = strdup(stringA);
for (char* p = stringB; *p; ++p) {
*p = tolower(*p);
}
这一行:
char* stringB = malloc(sizeof(char) * strlen(stringA));
应该是这样的:
char* stringB = malloc(sizeof(char) * (strlen(stringA) + 1));
那么你就可以复制stringA末尾的\0了
此外,您想要复制到文字字符串 - 即分段错误
char *strncpy(char *dest, const char *src, size_t n)
我会尝试在您自己的代码中评论并更正我看到的错误:
(我不会更正那些可以消除或以其他方式更好地完成的事情,但它们是正确的或无害的,所以你只会看到 必须 更正的内容,因为编程错误,而不是关于风格或编程用途的问题)
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main() {
char* stringA = "someVeryinTeresTingString";
/* you need to consider the space for the final null character in the malloc() call */
char* stringB = malloc(sizeof(char) * (strlen(stringA) + 1));
/* you don't need to use sizeof(char) as it is always equal to one.
* Multiplying by one is not necessary, but you'll probably know.
* char is warranteed by C standard that its sizeof is one. */
/* you need to copy the string *before* printing, or you will print an
* uninitialized string. Or at least initialize stringB to zeros, so you can
* use it with printf like functions (I do initialize the first char position to
* zero to make it appear as a length zero "" string)
* You will incurr in undefined behaviour if you don't do this. */
stringB[0] = '[=10=]';
printf("A: %s, B: %s\n", stringA, stringB);
/* you need to copy the strings, so you can do it better if you test when
* stringA[i] == '[=10=]', so you don't calculate the length of a string that is
* not going to change at every loop iteration. I will not change your
* code, because this is not an error. But strlen() searches from the
* beginning of the string for the '[=10=]' char, character by character,
* and this test is done at every loop iteration. With the expression
* stringA[i] == 0 you do only a test per loop iteration to see if
* the char at position i in stringA is the null character. */
int i;
for (i = 0; i < strlen(stringA); i++) {
stringB[i] = tolower(stringA[i]);
}
/* you have not copied the final '[=10=]', so I do it now. I need to move the
* declaration of i outside of the loop to be able to use it's value. */
stringB[i] = 0; /* you can use 0 or '[=10=]' interchangeably */
printf("A: %s, B: %s\n", stringA, stringB);
/* nope. you need to copy the strings with a normal strcpy() as you know that
* both are the same length (better, you know that the space in stringB
* is the same as the length of stringA plus one). If you do this, you will not copy the last '[=10=]' char, so wee need to append it.
* well, I don't know if that is what you want, so I don't actually touch anything here. */
strncpy(stringA, stringB, strlen(stringA) - 1);
/* stringB should be one char shorter than stringA */
printf("A: %s, B: %s\n", stringA, stringB);
}
顺便提一下,建议您使用 strdup(3)
。这是个好主意,在这种情况下您不需要考虑最终的空值,因为 strdup()
会处理它。请记住,strdup(3)
并未包含在许多 C 标准修订版中,因此如果您这样做,您可能会遇到麻烦
把你的程序移到一个没有它的地方(无论如何,这应该很奇怪)