2016-01-30 27 views
25

Właśnie napisałem mały program, który czyta argumenty linii poleceń w C, nic zbyt trudnego. Ja również je modyfikowałem, na przykład zmieniając pierwszy znak parametru na wielkie.Czy łańcuchy w argv można modyfikować?

Wiem, że nie powinieneś modyfikować literałów łańcuchowych, ponieważ może to powodować niezdefiniowane zachowanie, więc zastanawiałeś się, czy ciągi znaków w *argv[] są literałami, których nie powinieneś zmieniać.

int main(int argc, char *argv[]) 
+1

Możliwa duplikat [Jakie są argumenty do main() dla?] (Http://stackoverflow.com/questions/ 3734111/what-are-the-arguments-to-main-for) – user007

+5

To nie jest dosłowne. Możesz to zmienić. – BLUEPIXY

+0

Wiem, do czego służą i co mają na myśli, zastanawiając się, czy to nie były literały. –

Odpowiedz

25

Z C11 standardowym projekcie N1570, §5.1.2.2.1/2:

Parametry argc i argv i ciągi wskazywanego przez tablicy argv będzie Modi fi stanie przez program i zachowaj ich ostatnie zapisane wartości między uruchomieniem programu i zakończeniem programu.

Są one modyfikowalne. Oznacza to, że nie są literałami ciągów.

Ale uważać: górna cytat odnosi się tylko do wskaźników do struny, z wyłączeniem obowiązkowego wskaźnika pustego w argv[argc] .
Z C11 standardowym projekcie N1570, §5.1.2.2.1/2 (tak samo jak wyżej) :

argv[argc] będzie wskaźnikiem NULL


Uwagi:

  • coś w tym zdaniu:

    wiem, że nie należy modyfikować literały ciągów gdyż może to spowodować niezdefiniowanej zachowanie [...]

    „może”? To zawsze działa. Niezdefiniowane zachowanie obejmuje oczekiwane, jakby dobrze zdefiniowane i nieoczekiwane zachowanie.


Dzięki @black!

+1

Dziękuję za odpowiedź, wiem, że zawsze powoduje to niezdefiniowane zachowanie. Chyba powinienem zadać bardziej jednoznaczne pytanie, zmienię to teraz. –

+1

Czy to oznacza, że ​​same wskaźniki mogą zostać zmienione, czy nie? To znaczy. można zrobić: 'argv [0] = NULL' – 2501

+0

@ 2501 Dobre pytanie. IMO, "Parametry" argc "i" argv "oraz łańcuchy wskazane przez tablicę argv muszą być modyfikowane przez program [...]" odnoszą się tylko do samych liter "argc" i "argv" oraz do ciągów znaków. Wykopię trochę i zgłoś się. – Downvoter

4
int main(int argc, char *argv[]) 

argv jest szereg wskaźników do char (right left rule). Ale tablice, gdy są podane w argumentach funkcji, są traktowane jako wskaźnik do typu elementu tablicy, więc można powiedzieć, że jest to wskaźnik do wskaźnika do znaku. Więc zgodnie z podpisem głównego możesz go zmodyfikować. W przeciwnym razie musiał być wskaźnikiem do wskaźnika do constant char.

Również przez definition, który nie jest literałem ciąg.

+3

(Wiem, że to C i C++! = C ale) w C, możesz napisać 'char * str =" foo ";' i modyfikowanie 'str' jest nadal niezdefiniowanym zachowaniem. – Downvoter

+0

@ cad ok, ale zamiast głównej miałby dziwny podpis –

+2

@ cad Dotyczy to również C++. Konwersja z literału ciągłego na "char *" nie jest zabroniona, tylko przestarzała. – emlai

3

Tablice obsługujące ciągi znaków w argv można modyfikować.
Ale nie masz możliwości poznania ich rozmiarów.

Byłbym niezadowolony widząc kod, który (próbuje) zwiększyć rozmiar ciągów.

#include <stdio.h> 
#include <string.h> 
// this program may behave erraticaly 
int main(int argc, char **argv) { 
    for (int k = 1; k < argc; k++) { 
     printf("original argv[%d] is %s\n", k, argv[k]); 
    } 
    printf("\n"); 
    for (int k = 1; k < argc; k++) { 
     strcat(argv[k], " foo"); // add foo to each argv string 
     printf("first modification to argv[%d] is %s\n", k, argv[k]); 
    } 
    printf("\n"); 
    for (int k = argc; k > 1; k--) { 
     strcat(argv[k - 1], " bar"); // add bar to each argv string 
     printf("final argv[%d] is %s\n", k - 1, argv[k - 1]); 
    } 
    return 0; 
} 

Na moim komputerze, nazywając ten program z one two three argumentów produkuje

 
original argv[1] is one 
original argv[2] is two 
original argv[3] is three 

first modification to argv[1] is one foo 
first modification to argv[2] is foo foo 
first modification to argv[3] is foo foo 

final argv[3] is foo foo bar 
final argv[2] is foo foo foo bar bar 
final argv[1] is one foo foo foo bar bar bar 
+0

Dzięki za to! Tak naprawdę nie zwiększałem ani nie zmniejszałem rozmiaru, tylko zmieniałem znak na małe lub duże litery. –