Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Возвращаемое значение указатель. Можно ли так сделать. 
V
    Опции темы
Alca
Дата 5.5.2008, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 25
Всего: 50



Можно ли так сделать?
Код

char *pszFunc() {
    char *pszResult = "";   
    strcpy(pszResult, "My_String");
    return pszResult;
}

Если через малок, то согласен ничего не освободится, а если просто обьявить. То да, все будет в куче, но по выходе из функции этот участок, будет отмечен как свободный, по этому гарантировать, что в том месте будет нужная информация нельзя.
Что это было????
Участок в "куче" может быть отмечен как "свободный" только в двумя способами - функцей free или командой delete.

Это сообщение отредактировал(а) Alca - 5.5.2008, 11:44


--------------------
PM WWW ICQ Skype Jabber   Вверх
EnergoHokum
Дата 5.5.2008, 11:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 600
Регистрация: 10.11.2006
Где: Россия, Ставропол ь

Репутация: нет
Всего: 6



Что-то мне подсказывает, что уже при strcpy может вылететь segfault. Ведь под pszResult у тебя зарезервирован всего-лишь 1 байт (для \0), а ты туда "My_String" скидываешь. Есть шанс затереть что-нить нужное, или просто влезть в чужую память, за что получишь по рукам от операционки.

Добавлено @ 11:54
Вот если сделать
Код

char* pszFunc()
{
    static char* pszResult[0xFF];//Вместо 0xFF подставить нужную длину, бОльшую, чем копируемая строка
    strcpy(&pszResult[0], "My_String");
    return &pszResult[0];
}

то из-за static результат будет доступен и после выхода из области видимости функции. Но будут проблемы при многопоточности, нужно или синхронизацию вводить, или переписать всё нафик по другому.

Это сообщение отредактировал(а) EnergoHokum - 5.5.2008, 11:57
PM MAIL ICQ   Вверх
Lazin
Дата 5.5.2008, 11:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 18
Всего: 154



Цитата(EnergoHokum @  5.5.2008,  11:50 Найти цитируемый пост)
Что-то мне подсказывает, что уже при strcpy может вылететь segfault

stack corruption

Добавлено через 10 минут и 28 секунд
Цитата(Alca @  5.5.2008,  11:18 Найти цитируемый пост)
Код

char *pszFunc() {
    char *pszResult = "";   
    strcpy(pszResult, "My_String");
    return pszResult;
}


а будет следующее
вызов strcpy - не приведет к segfault, так как произойдет обращение к памяти в стэке, причем будет перезаписана часть стека и возвращаемый указатель будет указывать на начало этой области.
далее, при попытке использовать этот указатель для чтения, очень велика вероятность получить мусор по этому указателю, так как эта область памяти будет перезаписана программой, туда будут записаны параметры функций, которые будут вызваны после pszFunc и их адреса возврата, если-же ты попытаешься изменить эту строку, то получишь stack corruption.  smile 

мне просто интересно, какие религиозные убеждения мешают использовать std::string(vector) или в случае Builder-a - AnsiString?

PM MAIL Skype GTalk   Вверх
Alca
Дата 5.5.2008, 12:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 25
Всего: 50



Цитата

использовать std::string(vector) или в случае Builder-a - AnsiString?

Скорость выполнения кода + совместимость с Visual C++ (AnsiString).

Это сообщение отредактировал(а) Alca - 5.5.2008, 12:31


--------------------
PM WWW ICQ Skype Jabber   Вверх
Lazin
Дата 5.5.2008, 12:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 18
Всего: 154



Цитата(Alca @  5.5.2008,  12:29 Найти цитируемый пост)
Скорость выполнения кода + совместимость с Visual C++

скорость выполнения кода больше не станет, скорее наоборот, так как std::string может реализовывать разные  оптимизации, например для коротких строк память может не выделяться или может использоваться механизм copy on write. 
В любом случае корректную программу сделать быстрой намного проще чем быструю корректной smile

Добавлено через 3 минуты и 59 секунд
я думаю основная идея твоего кода такова:
Код

char *pszFunc() {
    char *pszResult = "My_String";
    return pszResult;
}

но работать все равно не будет, так как строка размещается локально и при выходе из функции затрется, а из-за того, что возвращаемый указатель, не константный, может произойти повреждение стека (компилятор будет не против если ты туда что-нибудь запишешь)

Добавлено через 8 минут и 59 секунд
Код

std::string pszFunc() {
    std::string Result ("My_String");
    return Result;
}

в этом коде произойдет только одно выделение памяти - при создании строки память под строку выделиться в куче (где ей самое место), когда ф-я возвратит строку по значению копирования не произойдет, будет скопирован только объект Result копия которого получит указатель на массив в куче, содержащий строку "My_String"
PM MAIL Skype GTalk   Вверх
mrbrooks
Дата 5.5.2008, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

Репутация: 167
Всего: 306



Цитата

Добавлено через 3 минуты и 59 секунд
я думаю основная идея твоего кода такова:

Код

char *pszFunc() {
    char *pszResult = "My_String";
    return pszResult;

}


но работать все равно не будет, так как строка размещается локально и при выходе из функции затрется, а из-за того, что возвращаемый указатель, не константный, может произойти повреждение стека (компилятор будет не против если ты туда что-нибудь запишешь)


Тогда может вообще так:
Код

char *pszFunc() 
{
    return "My_String";
}

 smile  
PM MAIL   Вверх
Alca
Дата 5.5.2008, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 25
Всего: 50



Тест на конкатенацию строк: (тестировал ф-ей GetThreadTimes)
Код

#include <vcl.h>
#pragma hdrstop

#include <stdio.h>
#include <stdlib.h>
#include <iostream>     //STL 
#include <iomanip>      //STL 
#include <vector>       //STL 

#include <system.hpp>   //AnsiString
#include <Classes.hpp>  //TStringList
#include <SysUtils.hpp>

#include "Unit1.h"
#include "Classes\CPerform.h"
#include "Classes\CLog.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
//---------------------------------------------------------------------------
TfrmMain  *frmMain;
CPerform   P;
CLog       Log;
const int  ciTestNum = 1;
const int  ciLoopNum = 5000000;
//---------------------------------------------------------------------------
__fastcall TfrmMain::TfrmMain(TComponent* Owner) : TForm(Owner) {}
//---------------------------------------------------------------------------
__fastcall TfrmMain::~TfrmMain() {}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnStartClick(TObject *Sender) {
    switch (frmMain->rgStrings->ItemIndex) {
        case 0:
            vTestChar();
            break;

        case 1:
            vTestAnsiString();
            break;

        case 4:
            vTestStdString();
            break;
    }
    /*test*/P.vOpenLog();
}
//---------------------------------------------------------------------------
//vTestChar
void TfrmMain::vTestChar() {
    char pcRes[60]   = "";

    char pcTest1[] = "01234567890";
    char pcTest2[] = "qwertyuiop";
    char pcTest3[] = "!@#$%^&*()";
    char pcTest4[] = "xxxxxxxxxx";
    char pcTest5[] = "zzzzzzzzzz";

    /*test*/P.vStart(3);
    for (int i = 0; i < ciLoopNum; i ++) {
        strcpy(pcRes, "");
        strcat(pcRes, pcTest1);
        strcat(pcRes, pcTest2);
        strcat(pcRes, pcTest3);
        strcat(pcRes, pcTest4);
        strcat(pcRes, pcTest5);
    }
    /*test*/P.vStop();
}
//---------------------------------------------------------------------------
//vTestAnsiString
void TfrmMain::vTestAnsiString() {
    AnsiString asRes   = "";

    AnsiString asTest1 = "01234567890";
    AnsiString asTest2 = "qwertyuiop";
    AnsiString asTest3 = "!@#$%^&*()";
    AnsiString asTest4 = "xxxxxxxxxx";
    AnsiString asTest5 = "zzzzzzzzzz";

    /*test*/P.vStart(3);
    for (int i = 0; i < ciLoopNum; i ++) {
        asRes = asTest1 + asTest2 + asTest3 + asTest3 + asTest4 + asTest5;
    }
    /*test*/P.vStop();
}
//---------------------------------------------------------------------------
//vTestStdString
void TfrmMain::vTestStdString() {
    using namespace std;
    std::string sRes   = "";

    std::string sTest1 = "01234567890";
    std::string sTest2 = "qwertyuiop";
    std::string sTest3 = "!@#$%^&*()";
    std::string sTest4 = "xxxxxxxxxx";
    std::string sTest5 = "zzzzzzzzzz";

    /*test*/P.vStart(3);
    for (int i = 0; i < ciLoopNum; i ++) {
        sRes = sTest1 + sTest2 + sTest3 + sTest3 + sTest4 + sTest5;
    }
    /*test*/P.vStop();
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnOpenLogClick(TObject *Sender) {
    /*test*/P.vOpenLog();
}
//---------------------------------------------------------------------------

Результат тестирования:
[12:43:35:500]  00:00:07:046  <--- char
[12:44:20:00]    00:00:38:093  <--- AnsiString
[12:45:28:953]  00:01:00:718  <--- std::string


Это сообщение отредактировал(а) Alca - 5.5.2008, 12:59


--------------------
PM WWW ICQ Skype Jabber   Вверх
Lazin
Дата 5.5.2008, 13:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 18
Всего: 154



этот тест не совсем корректный, так как в случае char ты не обрабатываешь возможность переполнения буфера

Код

        strcpy(pcRes, "");
        strcat(pcRes, pcTest1);
        strcat(pcRes, pcTest2);
        strcat(pcRes, pcTest3);
        strcat(pcRes, pcTest4);
        strcat(pcRes, pcTest5);


под переменную pcRes выделено столько памяти, сколько нужно - заранее. в реальном приложении, работая с большим количеством строк, ты вряд-ли будешь знать сколько выделить под них памяти что-бы так-же уютно их сложить. 
к тому-же strcat можно использовать и с std::string (и даже с std::vector  smile )
PM MAIL Skype GTalk   Вверх
Lazin
Дата 5.5.2008, 13:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 18
Всего: 154



Цитата(Alca @  5.5.2008,  12:52 Найти цитируемый пост)
[12:43:35:500]  00:00:07:046  <--- char
[12:44:20:00]    00:00:38:093  <--- AnsiString
[12:45:28:953]  00:01:00:718  <--- std::string


проверь для случая 2х объединяемых строк, разница будет мало заметна.

Цитата(Alca @  5.5.2008,  12:52 Найти цитируемый пост)
asRes = asTest1 + asTest2 + asTest3 + asTest3 + asTest4 + asTest5;

в этом коде память будет выделяться 5 раз - под промежуточные результаты, и ты это сравниваешь с кодом
Цитата(Alca @  5.5.2008,  12:52 Найти цитируемый пост)
    char pcRes[60]   = "";
    char pcTest1[] = "01234567890";
    char pcTest2[] = "qwertyuiop";
    char pcTest3[] = "!@#$%^&*()";
    char pcTest4[] = "xxxxxxxxxx";
    char pcTest5[] = "zzzzzzzzzz";

в котором строки размещаются в стэке!!!

в реальных приложениях приходится работать со строками размещенными в динамической памяти, и оч. редко приходится объединять сразу много строк (хотя в этом случае легко заставить код работать быстро, просто нужно работать со строкой напрямую а не через операторы)
PM MAIL Skype GTalk   Вверх
Rififi
Дата 5.5.2008, 13:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1254
Регистрация: 9.3.2008

Репутация: 1
Всего: 36



ради интереса прогнал тот же тест
VS2008, Release
Опции оптимизации:
user posted image

код программы:

Код
#include "stdafx.h"

#include <string>
#include <string.h>
#include <time.h>
#include <iostream>
#include <iomanip>

static const size_t N = 1000000;
static const size_t BUF_SIZE = 1024;

static clock_t raw_char_test()
{
    char pcRes[BUF_SIZE] = {0};

    char pcTest1[] = "01234567890";
    char pcTest2[] = "qwertyuiop";
    char pcTest3[] = "!@#$%^&*()";
    char pcTest4[] = "xxxxxxxxxx";
    char pcTest5[] = "zzzzzzzzzz";

    clock_t t = clock();
    for (size_t i = 0; i < N; i++)
    {
        strncpy(pcRes, "", BUF_SIZE);
        strncat(pcRes, pcTest1, BUF_SIZE);
        strncat(pcRes, pcTest2, BUF_SIZE);
        strncat(pcRes, pcTest3, BUF_SIZE);
        strncat(pcRes, pcTest4, BUF_SIZE);
        strncat(pcRes, pcTest5, BUF_SIZE);
    }
    t = clock() - t;
    return (t);
}

static clock_t std_string_test()
{
    std::string sRes;
    sRes.reserve(BUF_SIZE);

    std::string sTest1 = "01234567890";
    std::string sTest2 = "qwertyuiop";
    std::string sTest3 = "!@#$%^&*()";
    std::string sTest4 = "xxxxxxxxxx";
    std::string sTest5 = "zzzzzzzzzz";

    clock_t t = clock();
    for (size_t i = 0; i < N; i++)
    {
        sRes = sTest1 + sTest2 + sTest3 + sTest3 + sTest4 + sTest5;
    }
    t = clock() - t;
    return (t);
}


int main()
{
    std::cout << N << " iterations." << std::endl;
    std::cout << "raw char: " << raw_char_test() / static_cast<double>(CLOCKS_PER_SEC) << std::endl;
    std::cout << "std::string: " << std_string_test() / static_cast<double>(CLOCKS_PER_SEC) << std::endl;
    return (0);
}


вывод (время в секундах):

Код
1000000 iterations.
raw char: 0.657
std::string: 15.245


Добавлено через 6 минут и 58 секунд
а теперь создадим невыгодные условия для raw_char :gigi:

Код
static clock_t raw_char_test()
{
    char pcRes[BUF_SIZE] = {0};

    clock_t t = clock();
    for (size_t i = 0; i < N; i++)
    {
        char* pcTest1 = new char[BUF_SIZE];
        char* pcTest2 = new char[BUF_SIZE];
        char* pcTest3 = new char[BUF_SIZE];
        char* pcTest4 = new char[BUF_SIZE];
        char* pcTest5 = new char[BUF_SIZE];

        strncpy(pcTest1, "01234567890", BUF_SIZE);
        strncpy(pcTest2, "qwertyuiop", BUF_SIZE);
        strncpy(pcTest3, "!@#$%^&*()", BUF_SIZE);
        strncpy(pcTest4, "xxxxxxxxxx", BUF_SIZE);
        strncpy(pcTest5, "zzzzzzzzzz", BUF_SIZE);

        strncpy(pcRes, "", BUF_SIZE);
        strncat(pcRes, pcTest1, BUF_SIZE);
        strncat(pcRes, pcTest2, BUF_SIZE);
        strncat(pcRes, pcTest3, BUF_SIZE);
        strncat(pcRes, pcTest4, BUF_SIZE);
        strncat(pcRes, pcTest5, BUF_SIZE);

        delete[] pcTest1;
        delete[] pcTest2;
        delete[] pcTest3;
        delete[] pcTest4;
        delete[] pcTest5;
    }
    t = clock() - t;
    return (t);
}



результат:

Код
1000000 iterations.
raw char: 26.952
std::string: 15.104


PM MAIL   Вверх
Lazin
Дата 5.5.2008, 13:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 18
Всего: 154



Цитата

1000000 iterations.
raw char: 0.374
std::string: 3.11
Press any key to continue . . .


Код

static clock_t std_string_test()
{
    std::string sRes;
    sRes.reserve(BUF_SIZE);
    std::string sTest1 = "01234567890";
    std::string sTest2 = "qwertyuiop";
    std::string sTest3 = "!@#$%^&*()";
    std::string sTest4 = "xxxxxxxxxx";
    std::string sTest5 = "zzzzzzzzzz";
    clock_t t = clock();
    for (size_t i = 0; i < N; i++)
    {
        //sRes.c = sTest1 + sTest2 + sTest3 + sTest3 + sTest4 + sTest5;
        sRes.append(sTest1);
        sRes.append(sTest2);
        sRes.append(sTest3);
        sRes.append(sTest4);
        sRes.append(sTest5);
        sRes.clear();
    }
    t = clock() - t;
    return (t);
}


Добавлено через 3 минуты и 14 секунд
Блин, это был debug

исправляюсь, вот relise 

Цитата

1000000 iterations.
raw char: 0.406
std::string: 0.407
Press any key to continue . . .

что и требовалось доказать  smile 
PM MAIL Skype GTalk   Вверх
Alca
Дата 5.5.2008, 14:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3993
Регистрация: 14.6.2006

Репутация: 25
Всего: 50



sRes.append() -  smile 
Уговорили. 
AnsiString нервно курит в сторонке...
Код

        asRes = "";
        asRes.cat_sprintf("%s%s%s%s%s", asTest1, asTest2, asTest3, asTest3, asTest4, asTest5);

Результат теста:
Код

[14:30:03:421]  00:00:18:031


Это сообщение отредактировал(а) Alca - 5.5.2008, 18:29


--------------------
PM WWW ICQ Skype Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0625 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.