1 Востаннє редагувалося Ярослав (10.02.2013 19:27:23)

Тема: Використання argc та *argv[]

Вітаю форумчани.
Маю код із книги КіР:

#include <stdio.h>
#include <string.h>
#define MAXLINE 1000

int getline(char *line, int max);

int main(int argc, char *argv[])
{
    char line[MAXLINE];
    int found = 0;

    if(argc != 2)
        printf("Use sample in find\n");
    else
        while(getline(line, MAXLINE) > 0)
            if(strstr(line, argv[1]) != NULL){
                printf("%s", line);
                found++;
            }
    return found;
}

int getline(char *s, int max){
    int i=0;
    while((*s = getchar()) != '\n' && *s != EOF && i < max-1){
        s++;
        i++;
    }
    *s = '\0';
    if(*s == EOF)
        return 0;
    return i;
}

Але нажаль не знаю як перевірити його дієздатність.
Працюю в Pelles C компіляторі і при запуску програми отримую повідомлення Use sample in find.
І одразу ж наступне про те, що я маю натиснути будь-яку кнопку для виходу із програми.
Запустивши cmd.exe я зміг протестувати властивості argc та *argv[] за допомогою команди echo.
Проте як перевірити роботу коду з прикладу вище поки що уявлення не маю.

2

Re: Використання argc та *argv[]

Я теж  є прихильником Pelles C компілятора, тому не розумію чого вам не вистачає.
Щоб задати параметри командного рядка зайдіть до project -> project options.. -> command line arguments вкладки General

3

Re: Використання argc та *argv[]

До речі, чи консольну програму ви створюєте? Чому ви не користуєтесь вбудованим дебагером? Навіщо використовувати команду echo.?

4

Re: Використання argc та *argv[]

Очі.завидющі, я не так давно вивчаю програмування, Сі - моя перша мова, а Pelles C - перший компілятор, тому так.
По всім іншим питанням, основною книгою для вивчення мови є КіР, команда echo і цей код - це все завдання і приклади із книги.

5

Re: Використання argc та *argv[]

Дебагером користуватись не вмію.

6

Re: Використання argc та *argv[]

Значення found дістається, якщо запустити програму в консолі:

> myprog.exe
.....//any text made by programme
> echo %errorlevel%

Але я так і не зрозумів, що цей код загалом покликаний зробити.

*s = '\0';
    if(*s == EOF)
        return 0;

Яка ймовірність того, що виконається цей return? :)

З.І: зневадник (дебаггер) - не панацея. Я взагалі ним не користуюся останні півроку-рік: завдяки юніт-тестам практично нема потреби.

7

Re: Використання argc та *argv[]

@Bartash
Я ним теж рідко користуюсь, окрім випадків зворотньої інженерії чужих програм. Але keithfay початківець, який його в очі не бачив і погано уявляє собі хід виконання програми.

8

Re: Використання argc та *argv[]

Очі.завидющі написав:

@Bartash
Я ним теж рідко користуюсь, окрім випадків зворотньої інженерії чужих програм. Але keithfay початківець, який його в очі не бачив і погано уявляє собі хід виконання програми.

Зрозуміти порядок виконання коду можна і на базі Visual Studio: вона дозволяє сконцентруватися на парадигмах програмування, а не на технічних деталях, що для початківця є важливим. І логіку роботи зневадника легше у студії зрозуміти, а у подальших міграціях лише налаштовувати його, а не вивчати з нуля. imho, зрештою. :)

З.І: сам я починав з VS 2003, після якої плин часу носив від ліліпутів до велетнів, аж поки не зупинив на березі Eclipse, стискаючи у руці потьмянілу лампу.

9

Re: Використання argc та *argv[]

Дякую Bartash та Очі!

10

Re: Використання argc та *argv[]

Іще один шматок коду, іще питання:

#include <stdio.h>
#include <string.h>
#define MAXLINE 1000

int getline(char *line, int max);

int main(int argc, char *argv[])
{
    char line[MAXLINE];
    long lineno = 0;
    int c, except = 0, number = 0, found = 0;

    while(--argc > 0 && (*++argv)[0] == '-')
        while(c = *++argv[0])
            switch(c){
                case 'x':
                    except = 1;
                    break;
                case 'n':
                    number = 1;
                    break;
                default:
                    printf("find: wrong parameter %c\n", c);
                    argc = 0;
                    found = -1;
                    break;
            }
    if(argc != 2)
        printf("Use: find -x -n sample\n");
    else
        while(getline(line, MAXLINE) > 0){
            lineno++;
            if((strstr(line, *argv) != NULL) != except){
                if(number)
                    printf("%ld:", lineno);
                printf("%s", line);
                found++;
            }
        }
    return found;
}

int getline(char *s, int max){
    int i=0;
    while((*s = getchar()) != '\n' && *s != EOF && i < max-1){
        s++;
        i++;
    }
    if(*s == EOF)
        return 0;
    *s = '\0';
    return i;
}

Більш-менш розібрався із теорією, проте не зовсім:
Ось декілька тверджень, дайте відповідь правильні чи ні:
1. argv - це покажчик на масив покажчиків, які в свою чергу вказують на рядкові константи.
2. Останній покажчик із масиву (на який вказує argv) покажчиків не визначений (за згодою).
3. argc - це кількість аргументів, тобто кількість рядкових констант, на які вказують покажчики із масиву покажчиків на який вказує argv.
4. *argv[argc] вказує на цей останній покажчик
5. argv[0] вкзає на покажчик, який вказує на рядкову константу ім'я програми
Абсолютно не розумію, що перевіряється в цьому виразі:
    while(--argc > 0 && (*++argv)[0] == '-')
Ми перевіряємо вектор аргументів, але чого індекс [0], цей же покажчик зарезервовано для імені програми.

11

Re: Використання argc та *argv[]

keithfay написав:

Ось декілька тверджень, дайте відповідь правильні чи ні:
1. argv - це покажчик на масив покажчиків, які в свою чергу вказують на рядкові константи.
2. Останній покажчик із масиву (на який вказує argv) покажчиків не визначений (за згодою).
3. argc - це кількість аргументів, тобто кількість рядкових констант, на які вказують покажчики із масиву покажчиків на який вказує argv.
4. *argv[argc] вказує на цей останній покажчик
5. argv[0] вкзає на покажчик, який вказує на рядкову константу ім'я програми
Абсолютно не розумію, що перевіряється в цьому виразі:
    while(--argc > 0 && (*++argv)[0] == '-')
Ми перевіряємо вектор аргументів, але чого індекс [0], цей же покажчик зарезервовано для імені програми.

1, 2, 4, 5 - вірно.
3 - кількість значущих аргументів - рядкових констант.
___________

while(--argc > 0 && (*++argv)[0] == '-')

Хитра форма проходження масиву циклом. Трактуйте проблемне місце як

(*(++argv))[0] == '-'

У цьому коді отримується доступ до наступного (преф-інкремент) рядка (розіменування), а далі аналізується його перший символ. Дефіс позначає, що поточний рядок містить назву параметру, себто наступний має містити його значення.

Ми перевіряємо вектор аргументів, але чого індекс [0], цей же покажчик зарезервовано для імені програми.

З.І: мабуть, ви випустили з виду розіменовувач. Порядок тут: Інкремент--Розіменування--Взяття за індексом.

12 Востаннє редагувалося Ярослав (12.02.2013 18:30:49)

Re: Використання argc та *argv[]

Доволі простим кодом зміг пояснити собі принцип застосування argc та *argv[] аргументів командного рядка
В рядок аргументів додаємо: Hello, world!

#include <stdio.h>

int main(int argc, char * argv[])
{
    printf("argc: %d\n", argc);
    printf("argv[0]: %s\n", *argv);
    printf("argv[1]: %s\n", *++argv);
    printf("argv[2]: %s\n", *++argv);
    printf("argv[3]: %s\n", *++argv);
    printf("argv[4]: %s\n", *++argv);
    return 0;
}

Вивід буде наступним

argc: 3
argv[0]: C:\Users\YaR\Desktop\Creative\Programming\C\practising\practising.exe
argv[1]: Hello,
argv[2]: world!
argv[3]: (null)
*** Process returned -1073741819 ***
Press any key to continue...

Із нього можна зрозуміти, що argc ініціалізується зі значенням 1, зустрічаючи пробіл або '\0' символ кінця рядку збільшується на 1, таким чином пробіл після Hello. +1, '\0' після world! +1. маємо argc = 3.
Відповідним адреси аргументів у вигляді рядкових констант передаються покажчикам:
Hello, -> argv[argc++]
world! -> argv[argc++]
Останній покажчик невизначений, як і було сказано раніше (Process returned -1073741819)
*argv[] - це просто масив покажчиків на char, точно такий же, як і будь-який інший в сі.
Останнє, що прошу мені пояснити:
На зображенні проілюстрована ідея про те, що argv - це покажчик на масив покажчиків, які в свою чергу вказують на рядкові константи. Але все це у мене асоціюється із двовимірним масивом, проте ж ми маємо одновимірний масив із назвою argv, який являється масивом покажчиків, чому на зображенні не намальовано так:
argv[0] ·--> echo\0
argv[1] ·--> Hello,\0
argv[2] ·--> world\0
argv[3] 0

Post's attachments

Безымянный.png 2.55 kb, 257 downloads since 2013-02-12 

13

Re: Використання argc та *argv[]

keithfay написав:

*argv[] - це просто масив покажчиків на char, точно такий же, як і будь-який інший в сі.
Останнє, що прошу мені пояснити:
На зображенні проілюстрована ідея про те, що argv - це покажчик на масив покажчиків, які в свою чергу вказують на рядкові константи. Але все це у мене асоціюється із двовимірним масивом, проте ж ми маємо одновимірний масив із назвою argv, який являється масивом покажчиків, чому на зображенні не намальовано так:
argv[0] ·--> echo\0
argv[1] ·--> Hello,\0
argv[2] ·--> world\0
argv[3] 0

Вимірність масивів - це певною мірою філософська категорія, тому що argv і сам "вважає" себе одновимірним, бо має інформацію лише про свої елементи-покажчики.
Та argv має подвійну природу. З одного боку, це - масив, з іншого - покажчик на покажчик, і саме тому схема на малюнку коректна. argv[0], argv[1] І т.д. не існують без власне argv. Вловлюєте думку? :)

14

Re: Використання argc та *argv[]

Я сам себе заплутав, тепер зрозуміло.