Почему операция ++ str вызывает ошибку, если массив имеет тип char * str [], но не в случае char * argv [] (один из аргументов основной функции)? - PullRequest
0 голосов
/ 08 октября 2019

Я написал небольшой кусочек кода, чтобы понять, как перемещаться по массиву указателей на символы и двумерному массиву символов. Я использовал 1] и 2] при печати o / p , чтобы просто отслеживать, какой блок кода печатает какой , любезно игнорируйте их.

Аналогичный код для печати o / p используется для обхода 3 различных (типов) массивов: -

a) Массив указателей символов: char * argv []

b) Массив указателей символов: char * str []

c) 2D-массив символов: char strarr [] [7]

Ниже приведены основные операции, которые я выполнил:char * foo [] затем

A) foo указывает 1-й элемент (строку) foo (сомнительно в этом)

B) * ++ foo указывает на 1-й символ следующего элемента foo

C) ** ++ foo дает 1-й символ следующего элемента foo

D) ++ * foo указывает на следующий символ в элементе foo

E) *++ * foo выдает следующий символ в элементе foo

Операции A, B, C & D разрешены только в случае char * argv []. char * str [] разрешает только операции C & D;в то время как двумерный массив char strarr [] [7] не разрешает все AD.

Я понимаю, почему операции C & D разрешены для char * str [], а не для char strarr [] [7]:char * str [] является указателем массива, и допускается приращение значения его элементов (т. е. значения адреса к строке), в то время как в случае char strarr [] 2 [7] является двумерным массивом элемента, невозможно увеличитьадрес его элементов.

Исправьте меня за любые неправильные предположения.

Но я не могу понять, почему операция ** ++ str, * ++ strили ++ str не разрешено, тогда как ** ++ argv * ++ argv или ++ argv разрешено?

И argv, и str являются массивом указателей на символы, тогда почему такое разное поведение? (str указывает на str [0], тогда почему ++ str вызывает ошибку вместо указания на str [1]?) Является ли char * argv [] каким-то особым видом массива или операциями над ним, выполняемыми каким-либо другим способом / методом?

Когда я пишу ** ++ str, * ++ str или ++ str, компилятор выдает следующую ошибку:

gcc -Wall -c "TestProg.c" (вкаталог: / home / crownedeagle / Загрузки / CDAC C-CAT / C - Решения K & R) TestProg.c: в функции 'main': TestProg.c: 61: 33: ошибка: требуется значение l в качестве операнда приращения printf ("\ n1]\ n ** ++ str =% c ", ** ++ str);^

Вот код:

//Pointer of Array and Array Pointer Experimentation

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

int main(int argc, char *argv[])
{
    int i;
    if (argc == 7)
    {
        printf("\n");
        for (i = 0; i < argc; i++)
            printf("%s\t\t%p\n", argv[i], argv[i]);

        printf("\n0]\n**argv = %c", **argv);
        printf("\n*argv = %s", *argv);

        printf("\n1]\nargv = %p", argv);
        printf("\n*argv = %s", *argv);
        printf("\n**++argv = %c", **++argv);
        printf("\nargv = %p", argv);
        printf("\n*argv = %s", *argv);
        printf("\n**++argv = %c", **++argv);
        printf("\nargv = %p", argv);
        printf("\n*argv = %s", *argv);      

        printf("\n2]\nargv = %p", argv);
        printf("\n&(argv[0]) = %p", &(argv[0]));
        printf("\n*argv = %p", *argv);
        printf("\n&(**argv) = %p", &(**argv));

        printf("\n*++*argv = %c", *++*argv);
        printf("\n*argv = %s", *argv);

        printf("\nargv = %p", argv);
        printf("\n&(argv[0]) = %p", &(argv[0]));
        printf("\n*argv = %p", *argv);
        printf("\n&(**argv) = %p", &(**argv));

        printf("\nargv[0] = %s", argv[0]);

        printf("\n\n");

        for (i = 0; i < argc; i++)
            printf("%s\t\t%p\n", argv[i], argv[i]);
    }

    char *str[] = {"ABCDEF", "HIJKLM", "OPQRST", "VWXYZA", "123456"};

    printf("\n");
    for (i = 0; i < 5; i++)
            printf("%s\t\t%p\n", str[i], str[i]);

    printf("\n0]\n**str = %c", **str);
    printf("\n*str = %s", *str);

    //printf("\n1]\n**++str = %c", **++str);
    //printf("\n*str = %s", *str);

    printf("\n1]\nstr = %p", str);
    printf("\n&(str[0]) = %p", &(str[0]));
    printf("\n*str = %p", *str);
    printf("\n&(**str) = %p", &(**str));

    printf("\n*++*str = %c", *++*str);
    printf("\n*str = %s", *str);

    printf("\nstr = %p", str);
    printf("\n&(str[0]) = %p", &(str[0]));
    printf("\n*str = %p", *str);
    printf("\n&(**str) = %p", &(**str));

    printf("\nstr[0] = %s", str[0]);

    printf("\n\n");

    for (i = 0; i < 5; i++)
            printf("%s\t\t%p\n", str[i], str[i]);

    char strarr[][7] = {"ABCDEF", "HIJKLM", "OPQRST", "VWXYZA", "123456"};

    printf("\n");
    for (i = 0; i < 5; i++)
            printf("%s\t\t%p\n", strarr[i], strarr[i]);

    printf("\n0]\n**strarr = %c", **strarr);
    printf("\n*strarr = %s", *strarr);

    //printf("\n1]\n**++strarr = %c", **++strarr);
    //printf("\n*strarr = %s", *strarr);

    printf("\n1]\nstrarr = %p", strarr);
    printf("\n&(strarr[0]) = %p", &(strarr[0]));
    printf("\n*strarr = %p", *strarr);
    printf("\n&(**strarr) = %p", &(**strarr));

    //printf("\n*++*strarr = %c", *++*strarr);
    printf("\n*strarr = %s", *strarr);

    printf("\nstrarr = %p", strarr);
    printf("\n&(strarr[0]) = %p", &(strarr[0]));
    printf("\n*strarr = %p", *strarr);
    printf("\n&(**strarr) = %p", &(**strarr));

    printf("\nstrarr[0] = %s", strarr[0]);

    printf("\n\n"); 

    for (i = 0; i < 5; i++)
            printf("%s\t\t%p\n", strarr[i], strarr[i]);

    return 0;   
}

Вывод кода:

crownedeagle@EagleNest:~/C - K&R Solutions$ ./TestProg abcdef hijklm opqrst vwxyza 123456 789012

    ./TestProg    0x7ffd61c027c7
    abcdef        0x7ffd61c027d2
    hijklm        0x7ffd61c027d9
    opqrst        0x7ffd61c027e0
    vwxyza        0x7ffd61c027e7
    123456        0x7ffd61c027ee
    789012        0x7ffd61c027f5

    0]
    **argv = .
    *argv = ./TestProg
    1]
    argv = 0x7ffd61c01c98
    *argv = ./TestProg
    **++argv = a
    argv = 0x7ffd61c01ca0
    *argv = abcdef
    **++argv = h
    argv = 0x7ffd61c01ca8
    *argv = hijklm
    2]
    argv = 0x7ffd61c01ca8
    &(argv[0]) = 0x7ffd61c01ca8
    *argv = 0x7ffd61c027d9
    &(**argv) = 0x7ffd61c027d9
    *++*argv = i
    *argv = ijklm
    argv = 0x7ffd61c01ca8
    &(argv[0]) = 0x7ffd61c01ca8
    *argv = 0x7ffd61c027da
    &(**argv) = 0x7ffd61c027da
    argv[0] = ijklm

    ijklm         0x7ffd61c027da
    opqrst        0x7ffd61c027e0
    vwxyza        0x7ffd61c027e7
    123456        0x7ffd61c027ee
    789012        0x7ffd61c027f5
    (null)        (nil)
    XDG_VTNR=7    0x7ffd61c027fc

    ABCDEF        0x400dfa
    HIJKLM        0x400e01
    OPQRST        0x400e08
    VWXYZA        0x400e0f
    123456        0x400e16

    0]
    **str = A
    *str = ABCDEF
    1]
    str = 0x7ffd61c01b80
    &(str[0]) = 0x7ffd61c01b80
    *str = 0x400dfa
    &(**str) = 0x400dfa
    *++*str = B
    *str = BCDEF
    str = 0x7ffd61c01b80
    &(str[0]) = 0x7ffd61c01b80
    *str = 0x400dfb
    &(**str) = 0x400dfb
    str[0] = BCDEF

    BCDEF         0x400dfb
    HIJKLM        0x400e01
    OPQRST        0x400e08
    VWXYZA        0x400e0f
    123456        0x400e16

    ABCDEF        0x7ffd61c01b50
    HIJKLM        0x7ffd61c01b57
    OPQRST        0x7ffd61c01b5e
    VWXYZA        0x7ffd61c01b65
    123456        0x7ffd61c01b6c

    0]
    **strarr = A
    *strarr = ABCDEF
    1]
    strarr = 0x7ffd61c01b50
    &(strarr[0]) = 0x7ffd61c01b50
    *strarr = 0x7ffd61c01b50
    &(**strarr) = 0x7ffd61c01b50
    *strarr = ABCDEF
    strarr = 0x7ffd61c01b50
    &(strarr[0]) = 0x7ffd61c01b50
    *strarr = 0x7ffd61c01b50
    &(**strarr) = 0x7ffd61c01b50
    strarr[0] = ABCDEF

    ABCDEF        0x7ffd61c01b50
    HIJKLM        0x7ffd61c01b57
    OPQRST        0x7ffd61c01b5e
    VWXYZA        0x7ffd61c01b65
    123456        0x7ffd61c01b6c

Ответы [ 2 ]

3 голосов
/ 08 октября 2019

В этом объявлении функции

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

компилятор настраивает параметр, имеющий массив с неизвестным типом размера, для указания на тип элемента. То есть это объявление эквивалентно

int main(int argc, char **argv )

Так что внутри функции вы имеете дело с указателем и можете применять операторы приращения или присваивания.

Например, эти объявления функции

void f( int a[100] );
void f( int a[10] );
void f( int a[] );

объявляет одну и ту же функцию, и все объявления корректируются компилятором в соответствии с объявлением

void f( int *a );

из стандарта C (6.7.6.3 Деклараторы функций (включая прототипы))

7 Объявление параметра как «массива типа» должно быть скорректировано на «квалифицированный указатель на тип», где квалификаторы типа (если таковые имеются) - те, которые указаны в [и]вывод типа массива. Если ключевое слово static также присутствует в [и] деривации типа массива, то при каждом вызове функции значение соответствующего фактического аргумента должно обеспечивать доступ к первому элементу массива с как минимум таким количеством элементов, как указановыражением размера.

В этом объявлении

char *str[] = {"ABCDEF", "HIJKLM", "OPQRST", "VWXYZA", "123456"};

объявлен массив типа char * [5]. Массивы являются неизменяемыми l-значениями. Поэтому вы не можете применять к операторам приращения или присваивания массивов.

0 голосов
/ 08 октября 2019

порядок выполнения мочевых операторов справа налево, поэтому:

* & + - ! ~ ++expr --expr

означает, что ++ выполняется сначала, а затем **.

относительно:

     printf("\n1]\n**++str = %c", **++str);

так, ++str приводит к указателю str[1]

, один раз отмените ссылку на него через '*', в результате строка, указанная нана str[1]

Вторая отмена ссылки через '*' приводит к появлению мусора в виде строки, где: str[1] points не является указателем

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...