C: 不影响指针的反向字符串函数
C: reverse string function not affecting pointer
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int reverse(char *, int);
main()
{
char *word = "Thanks for your help";
reverse(word, strlen(word));
printf("%s", word);
getchar();
}
int reverse(char *line, int len)
{
int i, j;
char *newline = malloc(strlen(line));
for (i = len - 1, j = 0 ; i >= 0; i--, j++)
{
newline[j] = line[i];
}
newline[j] = '[=10=]';
line = &newline;
}
大家好。我有一个简单的 C 问题,我似乎无法解决。
上面的程序是为了接收一个字符串并向后打印出来。 Reverse 是完成此操作的函数。
具体来说,问题是当我在 main() 中打印 word 时,字符串看起来没有变化。我试图将行地址设为换行地址,但没有任何效果。
int reverse(char *line, int len)
{
int i, j;
char *newline = malloc(strlen(line));
for (i = len - 1, j = 0 ; i >= 0; i--, j++)
{
newline[j] = line[i];
}
newline[j] = '[=10=]';
line = &newline; // Your problem is here
}
您只是在分配给本地 line
指针。这对调用函数没有任何影响。
改为考虑:
char *reverse(char *line, int len)
{
// ...
return newline;
}
补充建议:
- 打开编译器警告,并留意它们。你有很多小问题(例如
reverse
目前没有返回任何东西,但被声明为返回 int
)。
- 鉴于
reverse
的第一个参数是指向 C 字符串(以 NUL 结尾)的指针,因此也不需要采用长度参数。
reverse
函数不一定需要定义为 返回字符串的副本,反转 。它可以代替 就地 反转字符串。请注意,您不能 将字符串文字传递给这样的函数,因为它们是只读的。
我会这样写:
#include <stdio.h>
#include <string.h>
void reverse(char *str)
{
size_t i, j;
for (i = strlen(str) - 1, j = 0 ; i > j; i--, j++)
{
// Swap characters
char c = str[i];
str[i] = str[j];
str[j] = c;
}
}
int main(void)
{
// Mutable string allocated on the stack;
// we cannot just pass a string literal to reverse().
char str[] = "Here is a test string";
reverse(str);
printf("Result: \"%s\"\n", str);
return 0;
}
注意for
循环条件是i > j
,因为我们希望每次只遍历一半数组,而不是每个字符交换两次。
结果:
$ ./a.exe
Result: "gnirts tset a si ereH"
看看下面的代码:
void addOne(int a) {
int newA = a + 1;
a = newA;
}
int main() {
int num = 5;
addOne(num);
printf("%d\n", num);
}
你明白为什么会打印 5 而不是 6 了吗?这是因为当你将 num
传递给 addOne
时,你实际上复制了 num
。当 addOne
将 a
更改为 newA
时,它正在更改副本(称为 a
),而不是原始变量 num
。 C 具有按值传递语义。
您的代码遇到同样的问题(以及其他一些问题)。当您调用 reverse
时,会生成 word
的副本(不是字符串的副本,而是指向字符串的字符指针的副本)。当您将 line
更改为指向您的新字符串 newLine
时,您实际上并没有更改传入的指针;您正在更改指针的副本。
那么,应该如何实现逆向呢?这取决于:有几个选项。
reverse
可以 return 新分配的字符串包含原始字符串,反转。在这种情况下,您的函数签名将是 char *reverse
,而不是 int reverse.
reverse
可以就地修改原始字符串。也就是说,您永远不会分配新字符串,而只是简单地移动原始字符串的字符。这通常有效,但在您的情况下无效,因为用字符串文字初始化的 char 指针不一定指向可写内存。
- reverse 实际上可以将传入的指针更改为指向新字符串(您在当前代码中尝试执行的操作)。为此,您必须编写一个函数
void reverse(char **pointerToString)
。然后你可以分配*pointerToString = newLine;
。但这不是很好的做法。原来传入的参数现在不可访问,如果它被 malloc'd,它就不能被释放。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int reverse(char *, int);
main()
{
char *word = "Thanks for your help";
reverse(word, strlen(word));
printf("%s", word);
getchar();
}
int reverse(char *line, int len)
{
int i, j;
char *newline = malloc(strlen(line));
for (i = len - 1, j = 0 ; i >= 0; i--, j++)
{
newline[j] = line[i];
}
newline[j] = '[=10=]';
line = &newline;
}
大家好。我有一个简单的 C 问题,我似乎无法解决。
上面的程序是为了接收一个字符串并向后打印出来。 Reverse 是完成此操作的函数。
具体来说,问题是当我在 main() 中打印 word 时,字符串看起来没有变化。我试图将行地址设为换行地址,但没有任何效果。
int reverse(char *line, int len)
{
int i, j;
char *newline = malloc(strlen(line));
for (i = len - 1, j = 0 ; i >= 0; i--, j++)
{
newline[j] = line[i];
}
newline[j] = '[=10=]';
line = &newline; // Your problem is here
}
您只是在分配给本地 line
指针。这对调用函数没有任何影响。
改为考虑:
char *reverse(char *line, int len)
{
// ...
return newline;
}
补充建议:
- 打开编译器警告,并留意它们。你有很多小问题(例如
reverse
目前没有返回任何东西,但被声明为返回int
)。 - 鉴于
reverse
的第一个参数是指向 C 字符串(以 NUL 结尾)的指针,因此也不需要采用长度参数。 reverse
函数不一定需要定义为 返回字符串的副本,反转 。它可以代替 就地 反转字符串。请注意,您不能 将字符串文字传递给这样的函数,因为它们是只读的。
我会这样写:
#include <stdio.h>
#include <string.h>
void reverse(char *str)
{
size_t i, j;
for (i = strlen(str) - 1, j = 0 ; i > j; i--, j++)
{
// Swap characters
char c = str[i];
str[i] = str[j];
str[j] = c;
}
}
int main(void)
{
// Mutable string allocated on the stack;
// we cannot just pass a string literal to reverse().
char str[] = "Here is a test string";
reverse(str);
printf("Result: \"%s\"\n", str);
return 0;
}
注意for
循环条件是i > j
,因为我们希望每次只遍历一半数组,而不是每个字符交换两次。
结果:
$ ./a.exe
Result: "gnirts tset a si ereH"
看看下面的代码:
void addOne(int a) {
int newA = a + 1;
a = newA;
}
int main() {
int num = 5;
addOne(num);
printf("%d\n", num);
}
你明白为什么会打印 5 而不是 6 了吗?这是因为当你将 num
传递给 addOne
时,你实际上复制了 num
。当 addOne
将 a
更改为 newA
时,它正在更改副本(称为 a
),而不是原始变量 num
。 C 具有按值传递语义。
您的代码遇到同样的问题(以及其他一些问题)。当您调用 reverse
时,会生成 word
的副本(不是字符串的副本,而是指向字符串的字符指针的副本)。当您将 line
更改为指向您的新字符串 newLine
时,您实际上并没有更改传入的指针;您正在更改指针的副本。
那么,应该如何实现逆向呢?这取决于:有几个选项。
reverse
可以 return 新分配的字符串包含原始字符串,反转。在这种情况下,您的函数签名将是char *reverse
,而不是 int reverse.reverse
可以就地修改原始字符串。也就是说,您永远不会分配新字符串,而只是简单地移动原始字符串的字符。这通常有效,但在您的情况下无效,因为用字符串文字初始化的 char 指针不一定指向可写内存。- reverse 实际上可以将传入的指针更改为指向新字符串(您在当前代码中尝试执行的操作)。为此,您必须编写一个函数
void reverse(char **pointerToString)
。然后你可以分配*pointerToString = newLine;
。但这不是很好的做法。原来传入的参数现在不可访问,如果它被 malloc'd,它就不能被释放。