Консультация № 180480
28.10.2010, 20:17
52.36 руб.
0 26 2
Уважаемые эксперты!
У меня вопрос такого плана.
Пользователь запускает программу, указав числовой параметр в командной строке:
prog.exe 123
Программа prog.exe должна получить этот параметр, присоединить к строке и вывести значение переменной на экран. Примерно так:
str="Вы указали число: " $argv[1];
print str;

Вопросы такие:
1. Какой на ваш взгляд самый оптимальный способ вывести это экран?
2. Приведите пример реализации этого на C++.
3. Какой тип лучше всего подходит для переменной str?

Благодарю!

Обсуждение

Неизвестный
28.10.2010, 20:26
общий
Калашников О.А.:
Есть вопросы:
  • По какому критерию оценивается оптимальность?
  • Что делать если пользователь ввел не число?
давно
Профессор
230118
3054
28.10.2010, 20:28
общий
это ответ
Здравствуйте, Калашников О.А.!

Лучше всего использовать string из stl.
Код:


#include <iostream>
#include <string>
using namespace std;

int main(int argc, char* argv[])
{
string str="Your parameter was ";
if(argc>1)
{
str+=argv[1];
cout <<str;
}
return 0;
}
Неизвестный
28.10.2010, 20:31
общий
это ответ
Здравствуйте, Калашников О.А.!
Программа. Компилировал gcc.
Код:
/* 
* File: main.cpp
* Author: Micren
*
* Created on 28 Октябрь 2010 г., 19:23
*/

#include <iostream>
#include <string>

/*
*
*/
int main(int argc, char** argv)
{
std::string str = "Вы указали число:";
while (*++argv)
{
str = str + ' ' + *argv;
}
std::cout << str << std::endl;
return 0;
}

Пример работы:
Код:
~/NetBeansProjects/180480/dist/Debug/GNU-Linux-x86> ./180480 123 456 Вася:\)
Вы указали число: 123 456 Вася:)
давно
Руководитель
2
547
28.10.2010, 21:02
общий
Micren:
Оптимальность - на ваш взгляд.
Проверять, число или нет, не нужно. Будем считать, что пользователь всегда вводит число.
давно
Руководитель
2
547
28.10.2010, 21:10
общий
Micren:
Попробовал по Вашему примеру.
std::string buffer="!!!" + *argv;

Получил ошибку:
error C2110: '+' : cannot add two pointers

Среда MS VC++ 2008. Может быть не работает в этой среде?
Неизвестный
28.10.2010, 21:28
общий
Калашников О.А.:
Ну это не совсем по моему примеру. У меня складывается std::string с char*, а у Вас char* и char*. В первом случае происходит неявное преобразование. Т.к. std::string имеет соответствующий конструктор. Так что компилятор правильно написал.

Сделайте так:
Код:

std::string buffer=std::string("!!!")+*argv;


Но перед этим стоит сделать проверку на предмет существования параметра командной строки. У меня это выполняет цикл while. У Асмик if.
Так же первый параметр(имя программы) я пропускаю благодаря префиксной операции инкремента.
давно
Академик
20764
1861
28.10.2010, 21:30
общий
Цитата: Алексей Гладенюк
Попробовал по Вашему примеру.
std::string buffer="!!!" + *argv;

Получил ошибку:
error C2110: '+' : cannot add two pointers

Среда MS VC++ 2008. Может быть не работает в этой среде?

Это не работает в любой среде. Можно одно из слагаемых (или оба - это уже без разницы) явно преобразовать в std::string:
Код:
std::string buffer=std::string("Prefix: ") + *argv;

Но с эффективностью тут неважно: сначала оба операнда преобразуются из char* в std::string (а это связано с выделением динамической памяти), потом вычисляется конкатенация в новую строку (опять - с выделением памяти), потом строки-операнды уничтожаются (память освобождается обратно)
Единственное утешение -конструкция std::string buffer= - на самом деле не присваивание, а хитрая инициализация, и тут лишний экземпляр строки не создаётся.
давно
Профессор
230118
3054
28.10.2010, 21:37
общий
Можно добавить с помощью sprintf(buf, "!!! %d",str);
давно
Академик
20764
1861
28.10.2010, 21:40
общий
Цитата: Асмик Гаряка
Можно добавить с помощью sprintf(buf, "!!! %d",str);

Здесь можно легко нарваться на переполнение буфера.
Дополнение: тот компилятор, которым я пользуюсь, ещё укажет мне на несоответствие спецификатора формата и типа аргумента.
Неизвестный
28.10.2010, 21:53
общий
Хватов Сергей:
Но с эффективностью тут неважно: сначала оба операнда преобразуются из char* в std::string (а это связано с выделением динамической памяти), потом вычисляется конкатенация в новую строку (опять - с выделением памяти), потом строки-операнды уничтожаются (память освобождается обратно)
Единственное утешение - rjycnherwbz std::string buffer= - на самом деле не присваивание, а хитрая инициализация, и тут лишний экземпляр строки не создаётся.
Верно. Но можно слегка скрасить это дело. Заранее зарезервировав место для всей строки и использовать метод std::string::append(). Хотя operator+() и так его использует. Для эффективности лучше уж сделать это чисто на C без всякого ООП. Хотя вряд ли эффективность для этой задачи так уж важна.
давно
Руководитель
2
547
28.10.2010, 22:38
общий
Благодарю за информацию!
Оказывается не совсем это просто, как мне казалось.
Может сможете порекомендовать какую-нибудь литературу (или статью в интернете) по этой теме?
Неизвестный
28.10.2010, 22:55
общий
Г.Шилдт. "Полный справочник по С++"
Р.Лафоре. "Объектно-ориентированное программирование в C++" (лучше для первого знакомства)

Оказывается не совсем это просто, как мне казалось.
По сравнению с ассемблером?

На самом деле надо просто немного теории. Когда знаешь как это работает то все вполне понятно. Да и благо С++ дает возможность программировать в таком стиле какой требуется.
Неизвестный
28.10.2010, 23:29
общий
Калашников О.А.:
Цитата: Алексей Гладенюк
Проверять, число или нет, не нужно. Будем считать, что пользователь всегда вводит число.

точно. в параметрах всегда строка, нет смысла думать иначе..
вот два примера похожих.. но первый мне ближе
Код:

#include <stdio.h>

int main(int argc, char* argv[])
{
printf("Hi, you entered value: %s\n",(argc > 1)?argv[1]:"\rHi, you entered no value ");
return 0;
}
//---------------------------------------------------------------------------

Код:

#include <iostream.h>

int main(int argc, char* argv[])
{
string str ="";
cout <<(str = ((argc > 1) ? ( string("Hi, you entered value: ")+ argv[1]):string("Hi, you entered no value"))) << endl;
cin.get();
return 0;
}


В обоих случаях мы или выводим параметр, или сообщаем что ничего нет..
Неизвестный
28.10.2010, 23:44
общий
Калашников О.А.:
Очень хорошая книга, с точки зрения С++ & ООП & STL
"Объектно-ориентированное программирование на С++", АЙРА ПОЛ, Москва 1999, Бином.
Неизвестный
29.10.2010, 06:35
общий
Я бы сделал так:

Код:
#include <stdlib.h>
void main(int argc, char* argv[])
{
argv[0] = "ur param is : ";
while(argc--)
printf("%s ", argv[__argc - argc - 1]);
}


а ещё можно вместо первой строчки обозвать программу сразу "your parameter is - ", тогда ещё меньше кода

а еще "#include <stdlib.h>" можно тоже выкинуть, если хранить внешний параметр в верхнем слове первого аргумента. Но строчек будет столько же, а ассемблерного кода больше.

где моя медаль за лаконичность?
давно
Академик
20764
1861
29.10.2010, 08:21
общий
Цитата: 181465
где моя медаль за лаконичность?

У того, кто придумал __argc В "святцах" (ISO/IEC 9899:1999) этого нет, так что это изобретение какой-то конкретной платформы, и работать будет только там
Неизвестный
29.10.2010, 10:21
общий
Сандров Алекс:
Цитата: 181465
где моя медаль за лаконичность?
Да и речь, вообще, шла о C++, а не C. И не просто о выводе параметров, а о присоединении этих параметров к строке. Если сделаете это на С короче всех, то медаль гарантирована.
Неизвестный
29.10.2010, 13:17
общий
Цитата: Хватов Сергей
У того, кто придумал __argc В "святцах" (ISO/IEC 9899:1999) этого нет, так что это изобретение какой-то конкретной платформы, и работать будет только там


Эм. Это не вопрос. Выкидываем, вместе с #include :

Код:
void main(int argc, char* argv[])
{
argv[0] = "ur param is : ";
argc |= argc<<16;
while(argc-- & 0xffff)
printf(" %s", argv[(argc >> 16) - (0xffff & argc) - 1]);
}


А вот ещё более короткий вариант:

Код:
void main(int argc, char* argv[])
{
while(argc-- > 1)
argv[argc][-1] = 0x20;
printf("ur param is : %s", argv[1]);
}


ну если не даёте медаль за лаконичность, дайте хоть за отрицательные индексы в массивах
Неизвестный
29.10.2010, 13:47
общий
Сандров Алекс:
Оригинально.

Можно еще избавиться от сравнения.
Неизвестный
29.10.2010, 14:07
общий
Micren:
Угу, и там один пробел лишний вставляется, между первым и вторым аргументом. Вроде бы.
Неизвестный
29.10.2010, 16:42
общий
Сандров Алекс:
Цитата: 181465
while(argc-- > 1)
argv[argc][-1] = 0x20;
printf("ur param is : %s", argv[1]);

а теперь, встаньте на место компилятора, и покажите во что превратится сей вызов.
Вопрос был в простом - показать первый аргумент. При этом, мы допустили, что нет необходимости делать проверку на число.
И, если есть этот аргумент, то сохранить его в строке.
Не вижу ни только оптимальности в Вашем коде, но и сколь угодно практичности.

К тому же, говорить что "можно выкинуть" - не стоит, ибо мы не сказали о конкретном компиляторе, мы даже не упомянули ОС..
Неизвестный
01.11.2010, 06:11
общий
Victor Pyrlik:
Встал. И что?

Код:
18:   void main(int argc, char* argv[])
19: {
004010C0 push ebp
004010C1 mov ebp,esp
004010C3 sub esp,40h
004010C6 push ebx
004010C7 push esi
004010C8 push edi
004010C9 lea edi,[ebp-40h]
004010CC mov ecx,10h
004010D1 mov eax,0CCCCCCCCh
004010D6 rep stos dword ptr [edi]
20: while(argc-- > 1)
004010D8 mov eax,dword ptr [ebp+8]
004010DB mov ecx,dword ptr [ebp+8]
004010DE sub ecx,1
004010E1 mov dword ptr [ebp+8],ecx
004010E4 cmp eax,1
004010E7 jle main+38h (004010f8)
21: argv[argc][-1] = 0x20;
004010E9 mov edx,dword ptr [ebp+8]
004010EC mov eax,dword ptr [ebp+0Ch]
004010EF mov ecx,dword ptr [eax+edx*4]
004010F2 mov byte ptr [ecx-1],20h
004010F6 jmp main+18h (004010d8)
22: printf("ur param is : %s", argv[1]);
004010F8 mov edx,dword ptr [ebp+0Ch]
004010FB mov eax,dword ptr [edx+4]
004010FE push eax
004010FF push offset string "ur param is : %s" (00422034)
00401104 call printf (00401140)
00401109 add esp,8
23: }


Я не сильно стремился к оптимальности, но мне кажется, код мой не самый неоптимальный
Я просто хотел написать код как можно меньшего размера в с++(а не в асме), потому что первый и второй ответы уже дали исчервыпающий ответ вопрос.
давно
Руководитель
2
547
01.11.2010, 10:55
общий
Сандров Алекс:
Алекс, а Вы каким компилятором пользуетесь?
Это он может показать код так, как будет выглядеть в ассемблере?
Есть ли что-нибудь подобное в VC++?
Неизвестный
01.11.2010, 11:28
общий
Калашников О.А.:
Microsoft Visual C++ 6.0
Да, может.
Есть. Я делаю так, к примеру: ставлю брейкпоинт, например, тут, после функции main сразу. Потом, когда, программа встанет в ожидании, нажимаю Alt + 8, или из меню: View->Debug Window->Disassembly - появится окно с кодом в дизассемблере.
Ну и вообще, это окно с асм-кодом можно и не по брейкпоинту, а в любое время в процессе выполнения программы открыть. В нём будет код всего-всего, загруженного в виртуальное пространство процесса. Там же, в студии, можно ещё много разного делать. Посмотреть состояния регистров (Alt + 5), поставить брейкпоинты прямо на асм-команды, в том числе и в системных библиотеках(например, отловить вызов системной функции), посмотреть/поменять память (Alt + 6), посмотреть стек вызова функций (Alt + 7).

На всякий случай напомню, что asm-код в дебаге и релизе (ну и вообще, в по-разному настроенных сборках) будет отличаться.
давно
Руководитель
2
547
01.11.2010, 12:23
общий
Сандров Алекс:
Спасибо за важную информацию!
У меня MS Visual Studio 2008, там можно найти это в Debug -> Windows -> Disassembly в процессе отладки. Там же и регистры.
Очень полезная штука!
Неизвестный
01.11.2010, 12:30
общий
Калашников О.А.:
в 2008 студии - 4 окна просмотра памяти, что очень полезно бывает, особенно при глубоких дебагах
Форма ответа