简体   繁体   English

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] = '\0';
    line = &newline;
}

Hey folks. 嘿伙计。 I've got a simple C question that I can't seem to solve. 我有一个似乎无法解决的简单C问题。

The program above is meant to take in a string and print it out backwards. 上面的程序用于接收字符串并向后打印。 Reverse is the function by which this is done. 反向是完成此功能的功能。

The issue, specifically, is that when I print word in main(), the string appears unchanged. 具体地说,问题是当我在main()中打印单词时,字符串看起来没有变化。 I've attempted to make the address of line the address of newline, but it doesn't have any effect. 我试图将line的地址设置为newline的地址,但是它没有任何作用。

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] = '\0';
    line = &newline;             // Your problem is here
}

You're merely assigning to the local line pointer. 您只是分配给本地line指针。 This has no effect on the calling function whatsoever. 这对调用函数没有任何影响。

Consider instead: 考虑改为:

char *reverse(char *line, int len)
{
    // ...
    return newline;
}

Additional advice: 其他建议:

  • Turn on compiler warnings, and heed them . 打开编译器警告, 并注意它们 You've got lots of little things wrong (eg reverse isn't currently returning anything, but is declared as returning int ). 您有很多小错误(例如, reverse目前未返回任何内容,但被声明为return int )。
  • Given that the first argument of reverse is a pointer to a C string (NUL-terminated), there's no need to take a length argument as well. 鉴于reverse的第一个参数是一个指向C字符串(以NUL终止)的指针,因此也不需要采用length参数。
  • A reverse function doesn't necessarily need to be defined as returning a copy of the string, reversed . reverse函数不一定需要定义为返回字符串的副本reversed It could instead reverse a string in-place . 相反,它可以就地反转字符串。 Note that you cannot pass a string literal to a function like this, as they are read-only. 请注意,您不能将字符串文字传递给此类函数,因为它们是只读的。

Here's how I would write this: 这是我的写法:

#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;
}

Note that the for loop condition is i > j , because we want each to only traverse half the array, and not swap each character twice. 请注意, for循环条件是i > j ,因为我们希望每个循环仅遍历数组的一半,而不要交换每个字符两次。

Result: 结果:

$ ./a.exe
Result: "gnirts tset a si ereH"

Take a look at the code below: 看一下下面的代码:

void addOne(int a) {
   int newA = a + 1;
   a = newA;
}

int main() {
  int num = 5;
  addOne(num);
  printf("%d\n", num);
}

Do you see why that will print 5, and not 6? 您知道为什么会打印5,而不是6吗? It's because when you pass num to addOne , you actually make a copy of num . 这是因为当您将num传递给addOne ,实际上是制作了num的副本。 When addOne changes a to newA , it is changing the copy (called a ), not the original variable, num . addOnea更改为newA ,它将更改副本(称为a ),而不是原始变量num C has pass-by-value semantics. C具有按值传递的语义。

Your code suffers from the same problem (and a couple other things). 您的代码也遇到相同的问题(以及其他一些问题)。 When you call reverse , a copy of word is made (not a copy of the string, but a copy of the character pointer, which points to the string). 当您调用reverse ,将生成word的副本(不是字符串的副本,而是指向字符串的字符指针的副本)。 When you change line to point to your new string, newLine , you are not actually changing the passed-in pointer; 当您将line更改为指向新字符串newLine ,您实际上并没有更改传入的指针。 you are changing the copy of the pointer. 您正在更改指针的副本。

So, how should you implement reverse? 那么,您应该如何实施逆向? It depends: there are a couple options. 这取决于:有两种选择。

  1. reverse could return a newly allocated string containing the original string, reversed. reverse可以返回包含原始字符串的新分配的字符串,即为反向。 In this case, your function signature would be char *reverse , instead of int reverse. 在这种情况下,您的函数签名应为char *reverse ,而不是int reverse。
  2. reverse could modify the original string in place. reverse可以修改原始字符串。 That is, you never allocate a new string, and simply move the characters of the original string around. 也就是说,您永远不会分配新的字符串,而只需移动原始字符串的字符即可。 This works, in general, but not in your case because char pointers initialized with string literals do not necessarily point to writable memory. 通常,这是可行的,但不适用于您的情况,因为用字符串文字初始化的char指针不一定指向可写内存。
  3. reverse could actually change the passed-in pointer to point at a new string (what you are trying to do in your current code). reverse实际上可以更改传入的指针以指向新字符串(您在当前代码中尝试执行的操作)。 To do this, you'd have to write a function void reverse(char **pointerToString) . 为此,您必须编写一个函数void reverse(char **pointerToString) Then you could assign *pointerToString = newLine; 然后,您可以分配*pointerToString = newLine; . But this is not great practice. 但这不是一个好习惯。 The original passed-in argument is now inaccessible, and if it was malloc'd, it can't be freed. 现在无法访问原始传入的参数,并且如果已对其进行了malloc分配,则无法将其释放。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM