简体   繁体   English

在C中修改const char *

[英]Modify const char * in C

I am practicing for interviews. 我正在练习面试。 The problem Im currently stuck on is reversing a constant string in C. I know that since str2 is const, I can modify the location str2 points to, but not its value. Im当前遇到的问题是反转C中的常量字符串。我知道由于str2是const,因此我可以修改str2指向的位置,但不能修改其值。 I have a function below called reverse_const. 我下面有一个称为reverse_const的函数。 It will reverse the const char *str_const in place and print it. 它将const char * str_const反转到位并打印。 However, when I try to print st2 after reversal from the main method, the string isn't reversed anymore. 但是,当我尝试从main方法反转后打印st2时,字符串不再反转了。 Its like reverse_const() is temporarily changing the memory location of str2. 就像reverse_const()一样,它暂时更改了str2的存储位置。 What am I doing wrong here? 我在这里做错了什么?

#include <stdio.h>
#include <string.h>

void reverse(char *str){
    int c_size = strlen(str);
    char *c_begin = str, *c_end = str + (c_size - 1);

    int i;
    for(i = 0; i < c_size / 2; i++){
        *c_begin ^= *c_end;
        *c_end ^= *c_begin;
        *c_begin ^= *c_end;

        c_begin++;
        c_end--;
    }
}

void reverse_const(const char *str_const){
    int c_size = strlen(str_const);
    char str[c_size];
    strcpy(str, str_const);
    char *c_begin = str, *c_end = str + (c_size - 1);

    int i;
    for(i = 0; i < c_size / 2; i++){
        *c_begin ^= *c_end;
        *c_end ^= *c_begin;
        *c_begin ^= *c_end;

        c_begin++;
        c_end--;
    }

    str_const = str;
    printf("%s\n", str_const);
}

int main(){
    char str1[] = "Indiana";
    char *str2 = "Kentucky";
    printf("TESTS:\nString 1 pre-reversal: %s\n", str1);
    reverse(str1);
    printf("String 1 post-reversal: %s\n", str1);
    printf("Constant string 2 pre-reversal: %s\n", str2);
    reverse_const(str2);
    printf("Constant string 2 post-reversal: %s\n", str2);
}

When you pass by arguments, the function gets a copy. 当您传递参数时,该函数将获得一个副本。 str_const = str; assigns to that copy. 分配给该副本。 You could pass a pointer to pointer to be able change the value of a pointer outside of your function, however you're allocating the string copy on the stack, and therefore the string copy becomes invalid once you leave the scope of reverse_const so this wouldn't make sense here. 您可以将指针传递给指针,以能够在函数之外更改指针的值,但是您正在将字符串副本分配在堆栈上,因此一旦离开了reverse_const的范围,字符串副本将变为无效,因此这里没有道理。

If you want a string copy that survives the end of the reverse_const , allocate the array with malloc or do both the allocation and the copying with strdup . 如果您想让字符串副本在reverse_const的末尾reverse_const下来,请使用malloc分配数组,或者使用strdup进行分配和复制。 That you have to return the malloc'ed pointer somehow (by a return value of via a pointer to pointer argument) and the caller will then have the responsibility to free that malloc 'ed memory once it's done with it. 您必须以某种方式返回通过malloc malloc'ed指针(通过指向指针参数的指针的返回值),然后调用者将有责任在完成malloc分配的内存后free它。

You need to write your function so that you have some way to return the argument modified. 您需要编写函数,以便有某种方式返回修改后的参数。

One such solution is pass-by-reference : 一种这样的解决方案是通过引用传递

void reverse_const(const char **str_const){
    const char *in = *str_const;
    char *out = malloc(strlen(in)+1);

    /* write to out */

    *str_const = out;
}

But a better way would be to use the return value: 但是更好的方法是使用返回值:

char *reverse_const(const char *str_const){
    const char *in = str_const;
    char *out = malloc(strlen(in)+1);

    /* write to out */

    return out;
}

The return type could be const char * , but that's an unnecessary restriction since you know the returned string may be safely modified. 返回类型可以是const char * ,但这是不必要的限制,因为您知道可以安全地修改返回的字符串。

Note that both examples use malloc . 注意,两个示例都使用malloc Arrays cannot be passed back, in this manner, in C, as they exist on the stack and are destroyed when the function exits. 数组无法以这种方式在C语言中传回,因为它们存在于堆栈中,并在函数退出时销毁。

Whenever a long-running program uses malloc , there really ought to be a matching free somewhere in the code, or else you'll have a memory leak. 每当长时间运行的程序使用malloc ,在代码中的某处确实应该有一个匹配的free ,否则您将发生内存泄漏。 It's a pain, but something all C programmers must master. 这很痛苦,但是所有C程序员都必须掌握一些东西。

If you want the reversed str2 back in main() , you will either need to pass an adequately sized buffer to reverse_const to hold the reversed string, or you will need to dynamically allocate storage for it in reverse_const (a local variable length array won't do): 如果要在main()返回反转的str2 ,则需要将足够大小的缓冲区传递给reverse_const来保存反转的字符串,或者需要在reverse_const为其动态分配存储空间(局部变量长度数组不会做):

#include <stdlib.h>
...
void reverse_const (const char **str_const)
{
    int c_size = strlen (*str_const);
    char *str = calloc (c_size + 1, sizeof *str);
    strcpy (str, *str_const);
    char *c_begin = str, *c_end = str + (c_size - 1);

    int i;
    for (i = 0; i < c_size / 2; i++) {
        *c_begin ^= *c_end;
        *c_end ^= *c_begin;
        *c_begin ^= *c_end;

        c_begin++;
        c_end--;
    }

    *str_const = str;
    printf ("%s\n", *str_const);
}

int main (void) {

    char str1[] = "Indiana";
    char *str2 = "Kentucky";

    printf ("TESTS:\nString 1 pre-reversal: %s\n", str1);

    reverse (str1);

    printf ("String 1 post-reversal: %s\n", str1);
    printf ("Constant string 2 pre-reversal: %s\n", str2);

    reverse_const ((const char **)&str2);

    printf ("Constant string 2 post-reversal: %s\n", str2);

    free (str2);

    return 0;
}

Output 输出量

$ ./bin/revconststr
TESTS:
String 1 pre-reversal: Indiana
String 1 post-reversal: anaidnI
Constant string 2 pre-reversal: Kentucky
ykcutneK
Constant string 2 post-reversal: ykcutneK

Returning The Pointer 返回指针

You have an additional option to return the pointer to str to assign to str2 in main() . 您还有其他选择,可以将指向str的指针返回给main() str2 This is more what you would normally expect to see. 这通常是您期望看到的。 Let me know if you have any questions: 如果您有任何疑问,请告诉我:

char *reverse_const2 (const char **str_const)
{
    int c_size = strlen (*str_const);
    char *str = calloc (c_size + 1, sizeof *str);
    strcpy (str, *str_const);
    char *c_begin = str, *c_end = str + (c_size - 1);

    int i;
    for (i = 0; i < c_size / 2; i++) {
        *c_begin ^= *c_end;
        *c_end ^= *c_begin;
        *c_begin ^= *c_end;

        c_begin++;
        c_end--;
    }

    //*str_const = str;
    printf ("%s\n", *str_const);

    return str;
}

int main (void)
{

    char str1[] = "Indiana";
    char *str2 = "Kentucky";

    printf ("TESTS:\nString 1 pre-reversal: %s\n", str1);

    reverse (str1);

    printf ("String 1 post-reversal: %s\n", str1);
    printf ("Constant string 2 pre-reversal: %s\n", str2);

    str2 = reverse_const2 ((const char **)&str2);

    printf ("Constant string 2 post-reversal: %s\n", str2);

    free (str2);

    return 0;
}

The problem here is that you modify the argument passed to reverse_const , but arguments in C are passed by value meaning that they are copied. 这里的问题是您修改了传递给reverse_const的参数,但是C中的参数是按值传递的这意味着它们已被复制。 The variable you modify in the function is a copy of the original pointer, changing a copy will of course not change the original. 你在功能修改该变量是原始指针的副本 ,改变副本当然不会改变原来的。

C doesn't have pass by reference which is needed here, but it can be emulated by using pointers, in the case of your function you need to pass a pointer to the pointer, then use the dereference operator * to modify what the pointer to pointer points to, and use the address-of operator & when calling the function. C没有此处需要的按引用传递 ,但是可以通过使用指针进行模拟 ,对于函数,您需要将指针传递给指针,然后使用解引用运算符*修改指向的指针指针指向该函数,并在调用该函数时使用地址运算符&

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

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