2015-10-21 193 views
0

我正在爲面試練習。目前我遇到的問題是在C中反轉一個常量字符串。我知道既然str2是const,我可以修改str2的位置,但不能修改它的值。我有一個名爲reverse_const的函數。它將反轉const char * str_const並將其打印出來。但是,當我嘗試從main方法反轉後打印st2時,字符串不再被反轉。它就像reverse_const()暫時改變str2的內存位置。我在這裏做錯了什麼?修改C中的const char *

#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); 
} 
+0

'char str [c_size];'不足以保存長度爲'c_size'的* nul-terminated *字符串。 – Kninnug

+0

_我在這裏做錯了什麼?_你沒有做任何改變'str2'指向的地方。你已經知道你需要改變它的位置來解決這個問題......但是環境也很重要! 'str_const = str;'對'main()'上下文中的'str2'沒有影響。 – mah

+0

「我可以將位置str2點修改爲」不是如果該位置是恆定的。指針不是數組或字符串(並且數組不是字符串)。請閱讀一本好C書中的指針,數組和字符串文字。 – Olaf

回答

2

如果要反轉str2main(),則要麼需要一個足夠大緩衝器傳遞給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; 
} 

輸出

$ ./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 

Returnin克將指針

您有更多的選擇,指針返回str分配給str2main()。這更多的是你通常期望看到的。如果您有任何問題,請告知我們:

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; 
} 
+0

如果你將指針返回到反向字符串,而不是覆蓋'str2',我想'reverse_const'函數更多。 –

+0

同意,我只是在使用函數的形式,並不知道這是否會改變。 –

+0

@JohnBode - 添加返回作爲第二個例子。 –

1

這裏的問題是,你修改傳遞到reverse_const的說法,但在C參數通過值傳遞這意味着它們被複制。你在函數中修改的變量是拷貝的原始指針,改變拷貝當然不會改變原來的。

C沒有通通過這裏需要參考,但它可以通過使用指針,在函數的情況下,模擬你需要一個指針傳遞到指針,然後使用解引用運算符*修改指向指針的指針,並在調用函數時使用運算符&的地址。

2

當您通過參數傳遞時,函數會獲得副本。 str_const = str;分配給該副本。你可以傳遞一個指向指針的指針,以便能夠改變函數外部的指針值,但是你要在堆棧中分配字符串副本,因此一旦離開reverse_const的範圍,字符串副本就會失效,這裏沒有意義。

如果你想有一個字符串拷貝生存的reverse_const結束,分配陣列malloc或兩者都做了分配,並與strdup複製。您必須以某種方式返回malloc'ed指針(通過指向指針參數的指針的返回值),然後調用者將負責free,即malloc'一旦完成它就執行內存。

2

您需要編寫函數,以便您有一些方法來返回修改的參數。

的一個解決方案是傳遞通過引用

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

    /* write to out */ 

    *str_const = out; 
} 

但更好的方法是使用返回值:

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

    /* write to out */ 

    return out; 
} 

的返回類型可以是const char *,但這是一個不必要的限制,因爲你知道返回的字符串可能會被安全地修改。

請注意,這兩個示例使用malloc。數組不能以這種方式返回,因爲它們存在於堆棧中,並在函數退出時被銷燬。

每當長時間運行的程序使用malloc時,代碼中的某個地方確實應該匹配free,否則您將發生內存泄漏。這是一種痛苦,但所有C程序員都必須掌握的東西。

+0

任何使用內存分配而不提供釋放該分配的細節的建議對讀者來說通常是危險的(他們可能不瞭解動態分配足以查看完整需求)。 – mah

+1

公平點,現在固定。 – ams