void func(char *&buff) { buff = "abc"; } почему работает?
От: Аноним  
Дата: 22.08.07 20:17
Оценка: :)
Всем привет.

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

void func(char *&buff) { buff = "abc"; }

int main()
{
    char *p = 0;
    func(p);
    if (p != 0) cout << "true\n";

    return 0;
}


заранее спасибо.
Re: void func(char *&buff) { buff = "abc"; } почему работае
От: Пётр Седов Россия  
Дата: 22.08.07 21:34
Оценка:
Здравствуйте, Аноним.

В функции main есть переменная p. При вызове функции func ссылка buff привязывается (bind-ится) к переменной p. Функция func пишет в переменную p (косвенно, через ссылку buff) указатель на первый char строкового литерала "abc", этот первый char хранит код буквы «a» (в кодировке ASCII буква «a» кодируется числом 97). При выходе из функции func строковый литерал "abc" не исчезает, так как размещён статически, и переменная p продолжает указывать на него. Это позволяет засунуть строку в текстовый поток вывода std::cout, который выводит строку на консоль (по умолчанию).

А вообще лучше пользуйтесь каким-нибудь строковым классом, например std::string.
Пётр Седов (ушёл с RSDN)
Re: void func(char *&buff) { buff = "abc"; } почему работае
От: Аноним  
Дата: 23.08.07 01:06
Оценка:
А как-нибуть еще можно задачу эту по другому решить? (только не возвращая указатель)
Re[2]: void func(char *&buff) { buff = "abc"; } почему рабо
От: Alex Dav Россия  
Дата: 23.08.07 05:15
Оценка:
Здравствуйте, Пётр Седов, Вы писали:


ПС>...При выходе из функции func строковый литерал "abc" не исчезает, так как размещён статически, и переменная p продолжает указывать на него. ...


объясните, пожалуйста, почему? Вроде же в стеке должно было размещаться и при выходе из блока уничтожаться?
Спасибо.
Re[3]: void func(char *&buff) { buff = "abc"; } почему рабо
От: Smal Россия  
Дата: 23.08.07 06:11
Оценка:
Здравствуйте, Alex Dav, Вы писали:

AD>Здравствуйте, Пётр Седов, Вы писали:



ПС>>...При выходе из функции func строковый литерал "abc" не исчезает, так как размещён статически, и переменная p продолжает указывать на него. ...


AD>объясните, пожалуйста, почему? Вроде же в стеке должно было размещаться и при выходе из блока уничтожаться?

AD>Спасибо.

На стэк кладутся локальные переменные, а строковые литералы находятся в статической памяти и существуют
все время жизни программы.
С уважением, Александр
Re[3]: void func(char *&buff) { buff = "abc"; } почему рабо
От: rg45 СССР  
Дата: 23.08.07 06:26
Оценка:
Здравствуйте, Alex Dav, Вы писали:

AD>Здравствуйте, Пётр Седов, Вы писали:



ПС>>...При выходе из функции func строковый литерал "abc" не исчезает, так как размещён статически, и переменная p продолжает указывать на него. ...


AD>объясните, пожалуйста, почему? Вроде же в стеке должно было размещаться и при выходе из блока уничтожаться?

AD>Спасибо.

Для того, чтобы разместить массив символов на стеке, его нужно определить внутри функции именно как массив и, в этом случае, возврат ссылки или указателя на этот массив будет грубой ошибкой. Строковые литералы же располагаются в статической памяти программы и указатель на эти данные остается валидным как внутри, так и снаружи функции.
void func(char *&buff)
{
    char buffer[] = "Hello";  //массив символов размером в 6 элементов (не забываем про нулевой символ в конце) 
                              //создается в стеке и инициализируется литералом, хранящимся в статической памяти.
    
    buff = buffer;            //Ошибка: выдача наружу указателя на данные, хранящиеся в стеке
    
    buff = "Hello";           //Ok - "Hello woird" хранится не в стеке.
}
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: void func(char *&buff) { buff = "abc"; } почему рабо
От: Аноним  
Дата: 23.08.07 07:23
Оценка: -1
Здравствуйте, Аноним, Вы писали:

А>А как-нибуть еще можно задачу эту по другому решить? (только не возвращая указатель)

Какую задачу? Если строку возвратить, то вот
const char szAsked = "abc";

void GetStr(std::string& str)
{
    str = abc;
}

void GetStr(char* szBuf, int nBufSize)
{
    strcpy(szBuf, szAsked, nBufSize);
}

void GetStr(char** pszBuf)
{
    if (pszBuf) {
        // manual deallocation is required
        *pszBuf = new char[sizeof(szAsked)/sizeof(szAsked[0])];
        strcpy(*szBuf, szAsked, sizeof(szAsked)/sizeof(szAsked[0]));
    }
}
Re[3]: void func(char *&buff) { buff = "abc"; } почему рабо
От: alzt  
Дата: 23.08.07 08:13
Оценка:
Здравствуйте, Alex Dav, Вы писали:

AD>Здравствуйте, Пётр Седов, Вы писали:



ПС>>...При выходе из функции func строковый литерал "abc" не исчезает, так как размещён статически, и переменная p продолжает указывать на него. ...


AD>объясните, пожалуйста, почему? Вроде же в стеке должно было размещаться и при выходе из блока уничтожаться?

AD>Спасибо.

Уже ответили. Добавлю

char*p = "abc";
p[1] = 'B';


работает не так, как ожидалось (что "abc" находится в стеке).
Re[4]: void func(char *&buff) { buff = "abc"; } почему рабо
От: Smal Россия  
Дата: 23.08.07 08:18
Оценка:
Здравствуйте, alzt, Вы писали:

A>Уже ответили. Добавлю


A>
A>char*p = "abc";
A>p[1] = 'B';
A>


A>работает не так, как ожидалось (что "abc" находится в стеке).

Не работает, ибо менять данные строкового литерала нельзя.
С уважением, Александр
Re[2]: void func(char *&buff) { buff = "abc"; } почему рабо
От: Пётр Седов Россия  
Дата: 23.08.07 10:47
Оценка:
Здравствуйте, Аноним, Вы писали:
А>А как-нибуть еще можно задачу эту по другому решить? (только не возвращая указатель)
В C++ работать с текстом можно с помощью стандартных классов std::string и std::ostringstream, например:
#include <assert.h>
#include <string> // нет ".h"
#include <sstream>

using namespace std; // чтобы не писать std::string, std::ostringstream

// строка возвращается через результат функции
string MakeCowsText(int NumCows)
{
  assert(NumCows >= 0); // пред-условие
  switch (NumCows)
  {
  case 0: return "no cows"; // строковый литерал неявно преобразуется в std::string
  case 1: return "1 cow";
  default:
  {
    ostringstream s;
    s << NumCows << " cows"; // используется так же как std::cout
    return s.str(); // метод ostringstream::str возвращает накопленный текст как std::string
  }
  }
}

// строка возвращается через out-параметр (pText)
void MakeCowsText2(string* pText, int NumCows)
{
  assert(NumCows >= 0);
  switch (NumCows)
  {
  case 0: *pText = "no cows"; break;
  case 1: *pText = "1 cow"; break;
  default:
  {
    ostringstream s;
    s << NumCows << " cows";
    *pText = s.str();
  }
  }
}

int main()
{
  assert(MakeCowsText(/*NumCows:*/0) == "no cows");
  assert(MakeCowsText(/*NumCows:*/1) == "1 cow");
  assert(MakeCowsText(/*NumCows:*/2) == "2 cows");

  string Text;

  MakeCowsText2(&Text, /*NumCows:*/0);
  assert(Text == "no cows");

  MakeCowsText2(&Text, /*NumCows:*/1);
  assert(Text == "1 cow");

  MakeCowsText2(&Text, /*NumCows:*/2);
  assert(Text == "2 cows");

  return 0;
}
Пётр Седов (ушёл с RSDN)
Re[3]: Пётр Седов, с чем не согласен?
От: Аноним  
Дата: 23.08.07 14:17
Оценка:
Пётр Седов, с чем не согласен?
Re[5]: void func(char *&buff) { buff = "abc"; } почему рабо
От: alzt  
Дата: 23.08.07 14:58
Оценка:
Здравствуйте, Smal, Вы писали:

A>>
A>>char*p = "abc";
A>>p[1] = 'B';
A>>


A>>работает не так, как ожидалось (что "abc" находится в стеке).

S>Не работает, ибо менять данные строкового литерала нельзя.

Это я и имел в виду. Менять нельзя. Скомпилировать такое — без проблем.
А вот если бы "abc" находилось в стеке, то проблем не было бы.
Re[6]: void func(char *&buff) { buff = "abc"; } почему рабо
От: Smal Россия  
Дата: 23.08.07 15:01
Оценка:
Здравствуйте, alzt, Вы писали:

A>Здравствуйте, Smal, Вы писали:


A>>>
A>>>char*p = "abc";
A>>>p[1] = 'B';
A>>>


A>>>работает не так, как ожидалось (что "abc" находится в стеке).

S>>Не работает, ибо менять данные строкового литерала нельзя.

A>Это я и имел в виду. Менять нельзя. Скомпилировать такое — без проблем.

A>А вот если бы "abc" находилось в стеке, то проблем не было бы.
Проблемы появились бы при выходе из функции. Ты бы вернул указатель на временный объект.
Значительно уменьшить количество проблем позволит std::string.
С уважением, Александр
Re[4]: Пётр Седов, с чем не согласен?
От: Пётр Седов Россия  
Дата: 23.08.07 15:11
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Пётр Седов, с чем не согласен?


1.

const char szAsked = "abc";

szAsked — это указатель или массив? Если szAsked — указатель, то надо вписать звёздочку:
const char* szAsked = "abc";

Если szAsked — массив, то надо вписать квадратные скобки:
const char szAsked[] = "abc";


2.

void GetStr(std::string& str)
{
    str = abc;
}

Что такое abc? Если имелся в виду строковый литерал, то надо вписать двойные кавычки:
void GetStr(std::string& str)
{
    str = "abc";
}


3.

void GetStr(char* szBuf, int nBufSize)
{
    strcpy(szBuf, szAsked, nBufSize);
}

Стандартная C-шная функция strcpy принимает два параметра:
char* strcpy(char* pDest, const char* pSource);


4.

void GetStr(char** pszBuf)
{
    if (pszBuf) {
        // manual deallocation is required
        *pszBuf = new char[sizeof(szAsked)/sizeof(szAsked[0])];
        strcpy(*szBuf, szAsked, sizeof(szAsked)/sizeof(szAsked[0]));
    }
}

Во-первых, если szAsked — указатель, то sizeof(szAsked) = размер указателя в байтах (на 32-битной платформе скорее всего 4), а не размер массива char-ов.
Во-вторых, опять же, strcpy принимает два параметра.
В-третьих, что такое szBuf? (Скорее всего опечатка, имелось в виду pszBuf.)

По-моему, Ваш совет сбивает с толку новичка. Если бы я был новичком в C++, то я бы не хотел получить такой совет. За это и оценка «Не согласен» (минус).
Пётр Седов (ушёл с RSDN)
Re[7]: void func(char *&buff) { buff = "abc"; } почему рабо
От: alzt  
Дата: 23.08.07 15:46
Оценка:
Здравствуйте, Smal, Вы писали:

A>>>>
A>>>>char*p = "abc";
A>>>>p[1] = 'B';
A>>>>


A>>>>работает не так, как ожидалось (что "abc" находится в стеке).

S>>>Не работает, ибо менять данные строкового литерала нельзя.

A>>Это я и имел в виду. Менять нельзя. Скомпилировать такое — без проблем.

A>>А вот если бы "abc" находилось в стеке, то проблем не было бы.
S>Проблемы появились бы при выходе из функции. Ты бы вернул указатель на временный объект.
S>Значительно уменьшить количество проблем позволит std::string.

Это естественно, но я же никого не заставляю использовать временный объект.

Собственно мой пост был ответом на это:

ПС>>...При выходе из функции func строковый литерал "abc" не исчезает, так как размещён статически, и переменная p продолжает указывать на него. ...

AD>объясните, пожалуйста, почему? Вроде же в стеке должно было размещаться и при выходе из блока уничтожаться?

Т.е., если бы "abc" было в стеке, то в коде выше не было бы проблем, но "abc" уже исчезал бы в отличие от действительности.
Т.е. всё потому, что в стеке не располагается.
Re[5]: Пётр Седов, с чем не согласен?
От: Аноним  
Дата: 24.08.07 06:35
Оценка:
Здравствуйте, Пётр Седов, Вы писали:

[]

ПС>По-моему, Ваш совет сбивает с толку новичка. Если бы я был новичком в C++, то я бы не хотел получить такой совет. За это и оценка «Не согласен» (минус).


Да, согласен, описок много.
Спасибо за подробный ответ.
Re[3]: void func(char *&buff) { buff = "abc"; } почему рабо
От: Аноним  
Дата: 28.08.07 06:14
Оценка: 1 (1) +1
Здравствуйте, Пётр Седов, Вы писали:

ПС>Здравствуйте, Аноним, Вы писали:

А>>А как-нибуть еще можно задачу эту по другому решить? (только не возвращая указатель)
ПС>В C++ работать с текстом можно с помощью стандартных классов std::string и std::ostringstream, например:
ПС>
ПС>#include <assert.h>
ПС>#include <string> // нет ".h"
ПС>#include <sstream>

ПС>using namespace std; // чтобы не писать std::string, std::ostringstream

ПС>// строка возвращается через результат функции
ПС>string MakeCowsText(int NumCows)
ПС>{
ПС>  assert(NumCows >= 0); // пред-условие
ПС>  switch (NumCows)
ПС>  {
ПС>  case 0: return "no cows"; // строковый литерал неявно преобразуется в std::string
ПС>  case 1: return "1 cow";
ПС>  default:
ПС>  {
ПС>    ostringstream s;
ПС>    s << NumCows << " cows"; // используется так же как std::cout
ПС>    return s.str(); // метод ostringstream::str возвращает накопленный текст как std::string
ПС>  }
ПС>  }
ПС>}

ПС>// строка возвращается через out-параметр (pText)
ПС>void MakeCowsText2(string* pText, int NumCows)
ПС>{
ПС>  assert(NumCows >= 0);
ПС>  switch (NumCows)
ПС>  {
ПС>  case 0: *pText = "no cows"; break;
ПС>  case 1: *pText = "1 cow"; break;
ПС>  default:
ПС>  {
ПС>    ostringstream s;
ПС>    s << NumCows << " cows";
ПС>    *pText = s.str();
ПС>  }
ПС>  }
ПС>}

ПС>int main()
ПС>{
ПС>  assert(MakeCowsText(/*NumCows:*/0) == "no cows");
ПС>  assert(MakeCowsText(/*NumCows:*/1) == "1 cow");
ПС>  assert(MakeCowsText(/*NumCows:*/2) == "2 cows");

ПС>  string Text;

ПС>  MakeCowsText2(&Text, /*NumCows:*/0);
ПС>  assert(Text == "no cows");

ПС>  MakeCowsText2(&Text, /*NumCows:*/1);
ПС>  assert(Text == "1 cow");

ПС>  MakeCowsText2(&Text, /*NumCows:*/2);
ПС>  assert(Text == "2 cows");

ПС>  return 0;
ПС>}
ПС>


Вот после таких советов люди и начинают использовать std::string где ни попадя, совершенно не задумываясь о тяжелом механизме аллокации памяти, лежащем в основе использования динамических строк STL. Для многопоточных приложений, это может стать серьезной проблемой, так как реаллокации при создании — копировании строк естественно требуют межпоточной синхронизации и не факт, что в используемом STL она будет грамотно реализована.
Re[4]: void func(char *&buff) { buff = "abc"; } почему рабо
От: Пётр Седов Россия  
Дата: 29.08.07 15:58
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Вот после таких советов люди и начинают использовать std::string где ни попадя, совершенно не задумываясь о тяжелом механизме аллокации памяти, лежащем в основе использования динамических строк STL. Для многопоточных приложений, это может стать серьезной проблемой, так как реаллокации при создании — копировании строк естественно требуют межпоточной синхронизации и не факт, что в используемом STL она будет грамотно реализована.
Полностью согласен. Я вообще не использую STL и iostreams в серьёзном коде. Но если человек — начинающий или casual-ный программист, то лучше ему использовать стандартные библиотеки, так как про них очень много написано (книги, статьи, форумы).
Также, если человек раньше программировал на Delphi (или на любом другом высоко-уровневом языке со встроенным строковым типом) и переходит на C++, то ему будет привычно использовать какой-нибудь C++-ный строковый класс. Основной плюс std::string — стандартность, он доступен в любом современном компиляторе C++.
Пётр Седов (ушёл с RSDN)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.