Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Передать в функцию char*


Автор: Competitor 18.5.2006, 12:32
Как передать char* s в функцию в качестве модифицируемого параметра, т.е. чтобы после выполнения следующего кода:
Код

char *s;
func(s);
printf("%s", s);
...
void func(char *tem)
{
    int len;
    char* general="Privet";
    len=strlen(general);
    tem=new char[len+1];
    memcpy(tem, general, len);
    tem[len]='\0';
}


на экран выводилось "Привет". 

Автор: _hunter 18.5.2006, 12:34
передавать char** (или ссылку на char*) 

Автор: likehood 18.5.2006, 12:35
можно так:
Код

void func(char*& tem)


т.е. передаешь ссылку на указатель. 

Автор: Helicopterr 18.5.2006, 13:13
Competitor
сделай так:

Код
char* func(char *tem)
{
    char* general="Privet";
    strcpy(tem, general);
    return tem;
}

void main()
{
char s[100];
printf("%s", func(s));
}

 

Автор: Romikgy 18.5.2006, 13:20
Код

void func(char *tem)
{
    char* general="Privet";
    tem=general;
}
void main()
{
char *s;
func(s);
printf("%s", s);
}

А так разве нельзя?  

Автор: likehood 18.5.2006, 13:28
нельзя 

Автор: Romikgy 18.5.2006, 14:50
baronp, чего?
 

Автор: likehood 18.5.2006, 15:18
Цитата(Romikgy @  18.5.2006,  15:50 Найти цитируемый пост)
baronp, чего?

это был короткий ответ на твой предыдущий пост.
Объясняю почему нельзя: хоть tem и является указателем, это еще не значит, что его изменение даст эффект за пределами функции. Изменить можно только то, на что он указывает, а изменение самого указателя изменит лишь его локальную копию в данной функции. Внешний же указатель s при этом не изменится. Поэтому я и посоветовал в своем первом посте использовать ссылку на указатель. Главное не забыть освободить память, которая выделяется в функции func, но это уже другой разговор.

 

Автор: gruy 18.5.2006, 15:47
Romikgy, в твоем примере general при выходе из функции удалится. 

Автор: Romikgy 18.5.2006, 16:06
Цитата(gruy @  18.5.2006,  14:47 Найти цитируемый пост)
Romikgy, в твоем примере general при выходе из функции удалится. 

никуда оно не удалится , эта строка прописывается в исходном коде проги
baronp, Я хотел задать вопрос почему нельзя?

Цитата(baronp @  18.5.2006,  14:18 Найти цитируемый пост)
Объясняю почему нельзя: хоть tem и является указателем, это еще не значит, что его изменение даст эффект за пределами функции. Изменить можно только то, на что он указывает, а изменение самого указателя изменит лишь его локальную копию в данной функции

Откуда это все ? я понимаю если функция была вызвана как константная тогда да, а здесь вчем трабла? 

Автор: likehood 18.5.2006, 16:11
запусти свой вариант, убедись что не работает. Поставь между tem и звёздочкой амперсанд в прототипе функции и убедись что работает. Еще раз подумай почему. 

Автор: Romikgy 18.5.2006, 16:51
Каюсь  уже убедился, только нафига тогда придумали приставку const 

Автор: likehood 18.5.2006, 17:09
ты имеешь ввиду const перед указателем или const в конце прототипа функции? 

Автор: Earnest 18.5.2006, 19:45
Цитата(Romikgy @  18.5.2006,  17:51 Найти цитируемый пост)
нафига тогда придумали приставку const  

Путаешь теплое с мягким...
Вот пример:
Код

void foo (int a)
{
   a =10;
   // ...
}

void other()
{
   int N = 5;
   foo(N);
}

Как думаешь, изменится N после вызовы foo? Вот и с указателем то же самое: если переменная передается по значению, она копируется и меняется только ее копия (внутри функции), снаружи все сохраняется...
То, что вместо int у тебя указатель, ничего не меняет: его значение меняется только внутри функции. 

Автор: Romikgy 19.5.2006, 08:27
Цитата(Earnest @  18.5.2006,  18:45 Найти цитируемый пост)
меняется только ее копия (внутри функции)

Это я уже понял, мне интересно на кой тогда делать такой вызвов
void foo (const  int a)
 smile 
Ведь всеравно , что внутри менялось в наружу не выдет? зачем надо было так извращатся то? 

Автор: Daevaorn 19.5.2006, 09:05
Цитата(Romikgy @  19.5.2006,  09:27 Найти цитируемый пост)
Ведь всеравно , что внутри менялось в наружу не выдет? зачем надо было так извращатся то?  

Для самоконтроля программиста. Чтобы ненароком не записать в эту переменную что-либо. Но по сути, пользы от этого мало. 

Автор: Romikgy 19.5.2006, 09:28
Я смотрю в С много чего есть , правда пользы от него маловато, зато когда начинаешь об этом читать, голова может сварится smile 

Автор: likehood 19.5.2006, 10:28


Цитата(Daevaorn @  19.5.2006,  10:05 Найти цитируемый пост)
Для самоконтроля программиста. Чтобы ненароком не записать в эту переменную что-либо. Но по сути, пользы от этого мало.

Польза все же есть, вот пример:
Код

#include <stdio.h>

void func(const char *s) {
    s[0] = 'B';
}

void main() {
    char s[] = "Test string";
    func(s);
    puts(s);
}


Если оставить все как есть, получим ошибку компиляции: нельзя изменить значение по указателю s в функции func. Если же const убрать, получим Best string. 

Автор: Fazil6 19.5.2006, 10:41
Цитата

Для самоконтроля программиста. Чтобы ненароком не записать в эту переменную что-либо. Но по сути, пользы от этого мало. 

Цитата

Я смотрю в С много чего есть , правда пользы от него маловато, зато когда начинаешь об этом читать, голова может сварится

не все так просто и очевидно. 
Ты написал функцию 
int fffff(char* s);

теперь я пишу программу и применяю твою функцию. Я знаю, что часто указатель передается в функцию для того, чтобы туда был записан результат. Я не знаю как и что делает эта ф-я и я не знаю что будет лежать по этому указателю после вызова этой функции.
А вот если ты напишешь функцию
int fffff(const char* s);
у меня никаких сомнений нет по поводу того зачем передается указатель. Тоже самое относится и к аргументам  ссылкам.

 

Автор: Romikgy 19.5.2006, 10:55
Цитата(Fazil6 @  19.5.2006,  09:41 Найти цитируемый пост)
у меня никаких сомнений нет по поводу того зачем передается указатель

И зачем? 

Автор: Fazil6 19.5.2006, 11:06
Цитата

И зачем?

затем, что это аргумент для функции, а не буфер для результата. Затем, что передача ссылки(указателя) намного эфективнее чем передача значения при передаче классов/структур и классы обычно так и передаются 

Автор: Romikgy 19.5.2006, 12:11
Цитата(Romikgy @  19.5.2006,  09:55 Найти цитируемый пост)
Цитата(Fazil6 @  19.5.2006,  09:41 )у меня никаких сомнений нет по поводу того зачем передается указатель

это с 
Цитата(Fazil6 @  19.5.2006,  10:06 Найти цитируемый пост)
затем, что это аргумент для функции, а не буфер для результата

этим как то не соотносятся smile
Цитата(Fazil6 @  19.5.2006,  10:06 Найти цитируемый пост)
намного эфективнее чем передача значения

в чем эффективнее? 

Автор: Fazil6 19.5.2006, 12:43
хорошо. Начнем с конца.
Цитата

в чем эффективнее? 

допустим нам в функцию надо передать std::string
можно так
void fun(std::string str)
а можно и так
void fun(std::string* str)
результат будет одинаковый и в первом и во втором случае внутри функции мы получим необходимую строку, но в первом случае будет создан еще один объект, в этот объект будут копироваться все значения полей (все, что определено в конструкторе копии), а во втором будет передано значение адреса и все. Вызов второго варианта намного быстрее.
Цитата

этим как то не соотносятся 

прекрасно соотносится. В нашем 2-м варианте я не могу знать зачем передается указатель просто из соображений эфективности или для того, чтобы записать что-то по этому адресу, а если будет стоять const, то это значит, что функция говорит, что она не собирается изменять содержимое по этому адресу и буфером для результата это не является 

Автор: Любитель 19.5.2006, 13:00
Функции вида void func(const int a) действительно бессмысленны. const нужно для ссылок и указателей, чтобы гарантировать, что мы с помощью этой ссылки или указателя не изменим значение.
НО для указателя - указываемое значение, а не значение самого указтеля. 

Автор: Romikgy 19.5.2006, 13:32
Цитата(Fazil6 @  19.5.2006,  11:43 Найти цитируемый пост)
допустим нам в функцию надо передать std::stringможно такvoid fun(std::string str)а можно и такvoid fun(std::string* str)результат будет одинаковый и в первом и во втором случае внутри функции мы получим необходимую строку, но в первом случае будет создан еще один объект, в этот объект будут копироваться все значения полей (все, что определено в конструкторе копии), а во втором будет передано значение адреса и все. Вызов второго варианта намного быстрее.

Окей здесь вышло недопонимание терминов, об этом я знал давно
Цитата(Fazil6 @  19.5.2006,  11:43 Найти цитируемый пост)
прекрасно соотносится. В нашем 2-м варианте я не могу знать зачем передается указатель просто из соображений эфективности или для того, чтобы записать что-то по этому адресу, а если будет стоять const, то это значит, что функция говорит, что она не собирается изменять содержимое по этому адресу и буфером для результата это не является 

А с этим как то не совсем соглашусь, ты когда нибудь смотрел ассемблер код такой функции с const и без оной?
Посмотри ... он ничем не отличается smile, т.е. др. словами машиному коду все равно , в стеке остается результат, а вот компилятор (как я понял) за этим следит и выдает пердупреждения. 

Автор: Earnest 19.5.2006, 13:38
Именно это Fazil6 и говорит. const практически не влияет на сгенерированный код, это подсказка для программиста и компилятора.  

Автор: Fazil6 19.5.2006, 13:50
Цитата

А с этим как то не совсем соглашусь, ты когда нибудь смотрел ассемблер код такой функции с const и без оной?
Посмотри ... он ничем не отличается 

я и не заявляю, что const влияет на эфективность. я говорю совершенно о другом. если аргументом функции является const std::string*, то я понимаю, что указатель передается только  для того, чтобы не передавать сам объект по значению и данные менять не собираются, а если const не указан, то я буду предполагать, что внутри этой функции этот объект будут изменять и после вызова функции моя строка вполне возможно будет изменена.  Т.е. в случае когда в аргументах функции встречается указатель на константу, то компилятору это значит "нельзя менять содержимое", а для программиста вызывающего эту функцию это говорит: "содержимое не будет меняться" 

Автор: GremlinProg 19.5.2006, 14:00
Romikgy, раз уж ты о ассемблере заговорил, то наверняка понимаешь, что такое вызов cdecl. При очень плотной оптимизации, значения параметров с модификатором const могут не сохраняться дополнительно в стеке, а использоваться уже в другой функции. А теперь подумай, что будет, если ты вот такой параметр изменил: следующая по коду функция примет как будто тот же параметр, но на самом деле он будет изменен предыдущим вызовом. Это единственный случай, когда нужно помнить о const в параметрах типа void foo(int c). Остальное уже все рассказали, повторяться не буду. 

PS: оптимизация в сторону скорости работает по такому принципу только если ты ставишь const, в остальных случаях, все необходимые параметры сохраняются в стеке отдельно. Поэтому не пытайтесь изголяться с преобразованиями типа *(TYPE*)&c, где c - константа, ни к чему хорошему это не приведет, особенно, если вы таки используете оптимизацию компилятора. Подробно по всем опциям оптимизации написано в MSDN'е. 

Автор: Romikgy 19.5.2006, 15:15
Цитата(GremlinProg @  19.5.2006,  13:00 Найти цитируемый пост)
 то наверняка понимаешь, что такое вызов cdecl

Если честно то не сильно , я просто взял две фунции и посмотрел что получается на выходе.

Цитата(GremlinProg @  19.5.2006,  13:00 Найти цитируемый пост)
значения параметров с модификатором const могут не сохраняться дополнительно в стеке, а использоваться уже в другой функции

не понял?

Добавлено @ 15:17 
Цитата(Earnest @  19.5.2006,  12:38 Найти цитируемый пост)
 const 


Цитата(Earnest @  19.5.2006,  12:38 Найти цитируемый пост)
это подсказка для программиста и компилятора.  

Все более к этому склоняюсь

Цитата(Earnest @  19.5.2006,  12:38 Найти цитируемый пост)
 const практически не влияет

здесь можно по подробнее , на что влияет и когда? 

Автор: GremlinProg 19.5.2006, 15:45
cdecl - то вызов функции с передачей параметров в стеке. Вызывающий оператор сам очищает стек после вызова, поэтому параметры, которые он передаёт функции он может использовать повторно. Это одно из преимуществ, которое и породило thiscall.
Цитата

значения параметров с модификатором const могут не сохраняться дополнительно в стеке

Под этим я и подразумевал:
Цитата

параметры, которые он передаёт функции он может использовать повторно
 

Автор: Romikgy 19.5.2006, 15:54
Цитата(GremlinProg @  19.5.2006,  14:45 Найти цитируемый пост)
 Вызывающий оператор сам очищает стек после вызова,

понятно , а как очистить стек из С++ с модификатором 
Цитата(GremlinProg @  19.5.2006,  14:45 Найти цитируемый пост)
cdecl

 

Автор: GremlinProg 19.5.2006, 15:59
не понял вопроса, зачем тебе нужно его очищать? 

Автор: UnrealMan 20.5.2006, 10:06
Цитата
здесь можно по подробнее , на что влияет и когда?

Помимо сказанного выше другими, добавлю.
Если рассматривать const для ссылок, то он играет существенную роль. Например, если у тебя есть функция:
void Func(char *&p), ты не сможешь передать ей по ссылке константную строку или строку-массив
const char s1[] = "Text";
char s2[] = "Text";

Чтобы передать s1 (или просто "Text") либо s2, тебе придётся написать перед & слово const:
void Func(char *const &p).
Заодно ты запрещаешь изменение указателя p в своей функции. Для того, чтобы запретить ещё и изменение данных по этому указателю, надо дописать const где-то перед *
void Func(const char *const &p).

В случае передачи классовых объектов по ссылке без const у тебя не пройдёт ни одно неявное преобразование типа (к типам данных классов):

Код
struct Struct
{
    int n;
    Struct()  { n = 0; }
    Struct(int n) { this->n = n; }
};

void Func1(Struct &s) {}
void Func2(const Struct &s) {}

int main()
{
    Struct s;
    Func1(s); // нормально
    Func1((Struct)1); // нормально
    Func1(1); // ошибка
    Func2(1); // нормально
    return 0;
}
 

Автор: GremlinProg 20.5.2006, 10:22
UnrealMan, хорошее замечание! Про неявное преобразование я не знал 

Автор: UnrealMan 20.5.2006, 11:23
Цитата(UnrealMan @  20.5.2006,  10:06 Найти цитируемый пост)
В случае передачи классовых объектов по ссылке

Нда, и неклассовых, кстати, тоже:

Код
void Func1(double &n) {}
void Func2(const double &n) {}

int main()
{
    int n = 1;
    Func1(n); // ошибка
    Func2(n); // нормально
    return 0;
}

Правда, экономить на времени передачи параметров простейших типов, нагромождая их описанием const &, в большинстве случаев будет излишеством :-) 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)