C 如果使用函数中的指针反转字符串,则main中的输出将被篡改
我正在尝试使用Stephen Prata的C语言自学,本章结尾的练习之一是编写一个函数,用反转的字符串替换字符串的内容。。这是关于字符串的一章,有大量的指针。我尽可能多地使用指针,以便更好地理解,但我被卡住了 我的问题是,当我在main中打印返回指针的值时,它是乱码 当我使用gdbjust学习如何使用它时,我可以看到从我的函数返回的内存地址与在函数中使用的地址相同,并且它被分配给main中的指针,据我所知,这是正常的 我尝试了很多东西,我错过了什么?FWIW我还没有在这本书中了解到malloc,尽管我经常光顾各种各样的www页面,试图更好地理解CC 如果使用函数中的指针反转字符串,则main中的输出将被篡改,c,pointers,C,Pointers,我正在尝试使用Stephen Prata的C语言自学,本章结尾的练习之一是编写一个函数,用反转的字符串替换字符串的内容。。这是关于字符串的一章,有大量的指针。我尽可能多地使用指针,以便更好地理解,但我被卡住了 我的问题是,当我在main中打印返回指针的值时,它是乱码 当我使用gdbjust学习如何使用它时,我可以看到从我的函数返回的内存地址与在函数中使用的地址相同,并且它被分配给main中的指针,据我所知,这是正常的 我尝试了很多东西,我错过了什么?FWIW我还没有在这本书中了解到malloc,
$ cc -o exercise8 exercise8.c && ./exercise8
This is s1 before: abcd
This is s2 in function: dcba
This is s3 after: d`!
您返回一个指向本地变量的指针,自动变量以ISO标准术语表示,它是在堆栈上分配的,当您从函数返回时,内存被释放,留下一个指向内存的悬空指针,该内存可能包含也可能不包含您放在那里的字符串,这完全取决于环境。应该将输出缓冲区作为函数参数提供,或者用Malc分配它,或者用新的.< /P>用C++来分配它。
编辑;添加了一些示例代码
void reverse(const char* s1, char* s2) {
const int l = strlen(s1);
const char* p = s1 + l - 1;
do {
*s2++ = *p;
} while (p-- != s1);
*s2 = 0;
}
int main() {
// some code here
char s1[5] = "abcd";
char s2[5] = "";
reverse(s1, s2);
// some more code here
return 0;
}
或
您返回一个指向本地变量的指针,自动变量以ISO标准术语表示,它是在堆栈上分配的,当您从函数返回时,内存被释放,留下一个指向内存的悬空指针,该内存可能包含也可能不包含您放在那里的字符串,这完全取决于环境。应该将输出缓冲区作为函数参数提供,或者用Malc分配它,或者用新的.< /P>用C++来分配它。
编辑;添加了一些示例代码
void reverse(const char* s1, char* s2) {
const int l = strlen(s1);
const char* p = s1 + l - 1;
do {
*s2++ = *p;
} while (p-- != s1);
*s2 = 0;
}
int main() {
// some code here
char s1[5] = "abcd";
char s2[5] = "";
reverse(s1, s2);
// some more code here
return 0;
}
或
上面的代码将使s2指向堆栈上的字符串。函数完成后,此ar3变量将被删除
您应该输出到预先分配的某个变量。修改如下
int main(void)
{
char * s1 = "abcd";
char s3[5];
printf("This is s1 before: %s\n", s1);
str_rev(s1, s3);
printf("This is s3 after: %s\n", s3);
}
void str_rev(char * string, char * s2)
{
........
// don't return
// Also assign the last character with the NULL terminator
ar2[strlen(string)] = '\0';
}
当然,一旦你读到关于malloc的章节,你可以根据s1的长度为s3分配必要的内存。在那之前,请继续阅读并享受乐趣
上面的代码将使s2指向堆栈上的字符串。函数完成后,此ar3变量将被删除
您应该输出到预先分配的某个变量。修改如下
int main(void)
{
char * s1 = "abcd";
char s3[5];
printf("This is s1 before: %s\n", s1);
str_rev(s1, s3);
printf("This is s3 after: %s\n", s3);
}
void str_rev(char * string, char * s2)
{
........
// don't return
// Also assign the last character with the NULL terminator
ar2[strlen(string)] = '\0';
}
当然,一旦你读到关于malloc的章节,你可以根据s1的长度为s3分配必要的内存。在此之前,请继续阅读并享受乐趣。s2指向您的本地ar3阵列。因此,当str_rev返回时,通过s2查看ar3所在的内存不再有效。现在s2被称为悬空指针,这是学习正确使用C指针的巨大痛苦之一
对于不使用malloc且满足替换字符串内容的练习要求的简单解决方案,请尝试将结果复制到原始字符串的函数参数指针中;但是要小心,因为您当前的代码已经更改了指针字符串。您知道,此指针指向内存中有足够的字符,并且不是函数的本地指针。s2指向本地ar3数组。因此,当str_rev返回时,通过s2查看ar3所在的内存不再有效。现在s2被称为悬空指针,这是学习正确使用C指针的巨大痛苦之一
对于不使用malloc且满足替换字符串内容的练习要求的简单解决方案,请尝试将结果复制到原始字符串的函数参数指针中;但是要小心,因为您当前的代码已经更改了指针字符串。您知道,此指针指向内存,包含足够的字符,并且不是函数的本地指针。问题描述听起来好像您可以在适当的位置反转字符串。保持简单
void reverse_range(char *first, char *last) // [first, last)
{
for (; first != last && first != --last; ++first)
{
char temp = *first; *first = *last; *last = temp;
}
}
void reverse(char *str)
{
reverse_range(str, str + strlen(str));
}
int main()
{
char text[] = "0123456789";
printf("before: %s\n", text);
reverse(text);
printf("after : %s\n", text);
}
问题描述听起来像是可以在适当的位置反转字符串。保持简单
void reverse_range(char *first, char *last) // [first, last)
{
for (; first != last && first != --last; ++first)
{
char temp = *first; *first = *last; *last = temp;
}
}
void reverse(char *str)
{
reverse_range(str, str + strlen(str));
}
int main()
{
char text[] = "0123456789";
printf("before: %s\n", text);
reverse(text);
printf("after : %s\n", text);
}
问题的一部分在于,在处理字符串文字时,实际上无法用反转的字符串替换字符串的内容,即字符串的形式为char*s1=abcd
在不使用文字的情况下,我制作了一个相对容易理解的递归示例:
/* A function that replaces the contents of a string with the string reversed. */
#include <stdio.h>
#include <string.h>
void str_rev(char * string);
int main(void)
{
char s1[] = "abc";
char s2[] = "even";
char s3[] = "quodd";
printf("This is s1 before: %s\n", s1);
str_rev(s1);
printf("This is s1 after: %s\n", s1);
printf("This is s2 before: %s\n", s2);
str_rev(s2);
printf("This is s2 after: %s\n", s2);
printf("This is s3 before: %s\n", s3);
str_rev(s3);
printf("This is s3 after: %s\n", s3);
return 0;
}
void str_rev(char * string) {
//Store the first char of the string locally
char firstChar = string[0];
//Store the last char of the string locally
int lastCharPos = strlen(string)-1;
char lastChar = string[lastCharPos];
//Shorten the string (temporarily)
string[lastCharPos] = '\0';
if (string[1] != '\0') {
//Call on the now shortened string, eg.
//"abc" becomes "b"
//"even" becomes "ve"
//"quodd" becomes "uod"
str_rev(string+1);
}
//Swap the first and last characters
string[0] = lastChar;
string[lastCharPos] = firstChar;
}
问题的一部分在于,在处理字符串文字时,实际上无法用反转的字符串替换字符串的内容,即字符串的形式为char*s1=abcd
在不使用文字的情况下,我制作了一个相对容易理解的递归示例:
/* A function that replaces the contents of a string with the string reversed. */
#include <stdio.h>
#include <string.h>
void str_rev(char * string);
int main(void)
{
char s1[] = "abc";
char s2[] = "even";
char s3[] = "quodd";
printf("This is s1 before: %s\n", s1);
str_rev(s1);
printf("This is s1 after: %s\n", s1);
printf("This is s2 before: %s\n", s2);
str_rev(s2);
printf("This is s2 after: %s\n", s2);
printf("This is s3 before: %s\n", s3);
str_rev(s3);
printf("This is s3 after: %s\n", s3);
return 0;
}
void str_rev(char * string) {
//Store the first char of the string locally
char firstChar = string[0];
//Store the last char of the string locally
int lastCharPos = strlen(string)-1;
char lastChar = string[lastCharPos];
//Shorten the string (temporarily)
string[lastCharPos] = '\0';
if (string[1] != '\0') {
//Call on the now shortened string, eg.
//"abc" becomes "b"
//"even" becomes "ve"
//"quodd" becomes "uod"
str_rev(string+1);
}
//Swap the first and last characters
string[0] = lastChar;
string[lastCharPos] = firstChar;
}
这段代码无法编译。您仍然假设它将返回字符串,而不是将指针作为参数传递。哇,哇,不需要aggr
令人沮丧的否决票。不过,你的评论已经得到了适当的注意。我之所以咄咄逼人,是因为另一个正确的帖子被否决了。我记下这一条只是为了暂时得分,因为你的代码无法编译,可能会让新手感到沮丧。我不确定这是否有礼貌,我是新来的。我现在修改了投票结果,因为它已经编译好了。@stefan:我不确定它是否有礼貌。不,可能不是。对于那些完全错误或毫无帮助的答案,我保留我的反对票。小的编码错误或其他好答案中的打字错误最好在注释中标记出来。@Roddy Yeah。如果不是因为对正确答案投了完全错误的反对票,我就不会考虑投反对票。此外,在这种情况下,我不认为这是一个小错误,因为它只关注两个代码行。您仍然假设它将返回字符串,而不是将指针作为参数传递。哇,哇,不需要积极的向下投票。不过,你的评论已经得到了适当的注意。我之所以咄咄逼人,是因为另一个正确的帖子被否决了。我记下这一条只是为了暂时得分,因为你的代码无法编译,可能会让新手感到沮丧。我不确定这是否有礼貌,我是新来的。我现在修改了投票结果,因为它已经编译好了。@stefan:我不确定它是否有礼貌。不,可能不是。对于那些完全错误或毫无帮助的答案,我保留我的反对票。小的编码错误或其他好答案中的打字错误最好在注释中标记出来。@Roddy Yeah。如果不是因为对正确答案投了完全错误的反对票,我就不会考虑投反对票。此外,在这种情况下,我不认为这是一个小错误,因为它只关注两行代码的值。抱歉,但究竟为什么要递归地进行字符串处理,它不必要地使事情复杂化,更糟的是,不必要地对可以处理的字符串的长度施加人为限制。用一根长长的绳子打电话会让你脸上炸开一个巨大的烟囱。。。递归对于树和东西都是很好的,但对于字符串,按定义定义的字符串序列,为什么你会考虑它。@写一个函数,用字符串反转一个字符串的内容。我很高兴地注意到你的不符合这个规格。不过下次运气会好一些:事实上,我刚刚尝试了你们的程序,我得到了一些非常好的结果!对,事实上,我的代码中有一个小小的错误,现在已经全部修复,使得注释完全无效。。。嗯。这里仍然没有充分的理由使用任何递归性。还有,仅仅因为别人对你的答案发表了负面评论就否决了别人。。。我希望你能花点时间早点看其他答案,并对我的答案做出负面评论,这样我就可以早点解决它。顺便说一句,如果你能给我一个使用递归的好理由,我很乐意听你说。1这是一个练习,学习递归的概念很有用。2这个方法很有用,因为它假设没有malloc的先验知识。3符合问题中的规范。事实上,我更喜欢Blastfurne的答案。1如果你想教授递归的概念,请使用你实际使用它的上下文,比如一棵树。2我的第一个例子也是如此。3如果你喜欢另一个答案,就投票给另一个答案,不要仅仅因为你不喜欢就投票给其他东西。对不起,但你到底为什么要递归地处理字符串,它不必要地使事情复杂化,更糟糕的是,不必要地对你可以处理的字符串的长度施加人为限制。用一根长长的绳子打电话会让你脸上炸开一个巨大的烟囱。。。递归对于树和东西都是很好的,但对于字符串,按定义定义的字符串序列,为什么你会考虑它。@写一个函数,用字符串反转一个字符串的内容。我很高兴地注意到你的不符合这个规格。不过下次运气会好一些:事实上,我刚刚尝试了你们的程序,我得到了一些非常好的结果!对,事实上,我的代码中有一个小小的错误,现在已经全部修复,使得注释完全无效。。。嗯。这里仍然没有充分的理由使用任何递归性。还有,仅仅因为别人对你的答案发表了负面评论就否决了别人。。。我希望你能花点时间早点看其他答案,并对我的答案做出负面评论,这样我就可以早点解决它。顺便说一句,如果你能给我一个使用递归的好理由,我很乐意听你说。1这是一个练习,学习递归的概念很有用。2这个方法很有用,因为它假设没有malloc的先验知识。3符合问题中的规范。实际上我更喜欢高炉的答案。1如果你想教c
递归概念使用一个实际使用它的上下文,就像树一样。2我的第一个例子也是如此。3如果你喜欢另一个答案,就投票给另一个答案,不要仅仅因为你不喜欢就投票给那些东西。不管是谁先投了反对票,都可能因为这个原因投了反对票。在第一个代码示例中,printf%s\n,s1;给出输出abcd,并打印%s\n,s2;给出输出dcb。第二个例子更糟糕,在我的unix系统上导致了一个异常,堆栈跟踪以检测到的***glibc***./wich2:free:invalid pointer:0x0830b007***开头。更不用说,这两个示例即使有代码更正也不符合最初的规范:编写一个函数,用反转的字符串替换字符串的内容。。哦,好吧:我的第一次否决票^^^@William如果你真的指出代码中有问题,我会很高兴,这样我就可以修复它了,就像我现在所做的那样。这是我在飞行中写的,因为我还是人类,所以我会犯错误。事实上,第一次否决是在代码出现之前,我只是在代码中添加了说明如何进行字符串反转的内容。至于不进行就地反转,我之所以这样做是因为这是原始海报所针对的解决方案。无论是谁先投了反对票,都可能是因为这个原因而投了反对票。在第一个代码示例中,printf%s\n,s1;给出输出abcd,并打印%s\n,s2;给出输出dcb。第二个例子更糟糕,在我的unix系统上导致了一个异常,堆栈跟踪以检测到的***glibc***./wich2:free:invalid pointer:0x0830b007***开头。更不用说,这两个示例即使有代码更正也不符合最初的规范:编写一个函数,用反转的字符串替换字符串的内容。。哦,好吧:我的第一次否决票^^^@William如果你真的指出代码中有问题,我会很高兴,这样我就可以修复它了,就像我现在所做的那样。这是我在飞行中写的,因为我还是人类,所以我会犯错误。事实上,第一次否决是在代码出现之前,我只是在代码中添加了说明如何进行字符串反转的内容。至于不进行原地翻转,我之所以这样做是因为这是原始海报所针对的解决方案。
This is s1 before: abc
This is s1 after: cba
This is s2 before: even
This is s2 after: neve
This is s3 before: quodd
This is s3 after: ddouq
#include <stdio.h>
#include <string.h>
void my_strrev(char* begin){
char temp;
char* end;
end = begin + strlen(begin)-1;
while(end>begin){
temp = *end;
*end = *begin;
*begin = temp;
end--;
begin++;
}
}
main(){
char string[]= "foobar";
my_strrev(string);
printf("%s", string);
}