glutStrokeCharacter, похоже, искажает мою строку? [Дубликат]

Я не знаком с пакетом WriteXLS; Я обычно использую XLConnect:

library(XLConnect)
##
newWB <- loadWorkbook(
  filename="F:/TempDir/tempwb.xlsx",
  create=TRUE)
##
for(i in 1:10){
  wsName <- paste0("newsheet",i)
  createSheet(
    newWB,
    name=wsName)
  ##
  writeWorksheet(
    newWB,
    data=data.frame(
      X=1:10,
      Dataframe=paste0("DF ",i)),
    sheet=wsName,
    header=TRUE,
    rownames=NULL)
}
saveWorkbook(newWB)

Это, безусловно, может быть векторизованным, как отмечалось выше, как @joran, но только для быстрого создания динамических имен листов я использовал цикл for для демонстрации .

Я использовал аргумент create=TRUE в loadWorkbook, так как я создавал новый .xlsx-файл, но если ваш файл уже существует, вам не нужно указывать его, поскольку значение по умолчанию равно FALSE.

Вот несколько скриншотов созданной книги:

enter image description here [/g0]

enter image description here [/g1]

enter image description here [/g2]

22
задан Mr.C64 11 March 2014 в 18:32
поделиться

10 ответов

Поскольку этот вопрос отмечен C, сделайте следующее:

#define _POSIX_C_SOURCE 200809L
#include <string.h>

const char * returnCharPtr()
{
  std::string someString;

  // some processing!.

  return strdup(someString.c_str()); /* Dynamically create a copy on the heap. */
}

Не забудьте free() вернуть функцию, если она больше не используется.

5
ответ дан alk 24 August 2018 в 16:50
поделиться

Решение, которое не было вызвано в других ответах.

Если ваш метод является членом класса, например:

class A {
public:
    const char *method();
};

И если экземпляр класса будет жить за пределами полезности указателя, вы можете сделать:

class A {
public: 
    const char *method() {
        string ret = "abc";
        cache.push_back(std::move(ret));
        return cache.last().c_str();
    }
private:
    vector<string> cache; //std::deque would be more appropriate but is less known
}

Таким образом, указатели будут действительны до разрушения A.

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

1
ответ дан coyotte508 24 August 2018 в 16:50
поделиться

Хорошо, ПОЛНОСТЬЮ верна. Причина, по которой ваш текущий подход не срабатывает, заключается в том, что экземпляр std::string, созданный внутри функции, будет действителен только до тех пор, пока эта функция будет работать. Когда ваша программа покинет область действия, будет вызван деструктор std :: string, и это будет конец вашей строки.

Но если вы хотите, это C-строка, как насчет ...

const char * returnCharPtr()
{
    std::string someString;

    // some processing!.

    char * new_string = new char[someString.length() + 1];

    std::strcpy(new:string, someString.c_str());

    return new_string;
}

Но подождите ... это почти так же, как и возвращение std::string, не так ли?

std::string returnCharPtr()
{
    std::string someString;

    // some processing!.

    return new_string;
}

Это скопирует вашу строку в новую за пределами область действия. Он работает, но создает новую копию строки.

Благодаря оптимизации возвращаемого значения это не создаст копию (спасибо за все исправления!).

So , другой вариант - передать параметр в качестве аргумента, поэтому вы обрабатываете строку в функции, но не создаете новую копию. :

void returnCharPtr(std::string & someString)
{
    // some processing!.
}

Или, опять же, если вы хотите C-Strings, вам нужно следить за длиной вашей строки:

void returnCharPtr(char*& someString, int n) // a reference to pointer, params by ref
{
    // some processing!.
}
3
ответ дан jmac 24 August 2018 в 16:50
поделиться

Что происходит в этом коде:

const char * returnCharPtr()
{
    std::string someString("something");
    return someString.c_str();
}
  1. экземпляр std::string создан - это объект с автоматическим временем хранения
  2. указатель на внутренний память этой строки возвращается
  3. объект someString разрушен и внутренняя память очищена
  4. вызывающая сторона этой функции получает оборванный указатель (недействительный указатель), который дает неопределенное поведение

Лучшее решение: возвращает объект :

std::string returnString()
{
    std::string someString("something");
    return someString;
}
18
ответ дан LihO 24 August 2018 в 16:50
поделиться

Проблема заключается в том, что someString уничтожается в конце функции, а функция возвращает указатель на несуществующие данные.

Не возвращайте .c_str() строки, которая может быть уничтожена, прежде чем использовать возвращаемый указатель char.

Вместо ...

const char* function()
{
    std::string someString;
    // some processing!
    return someString.c_str();
}

//...

useCharPtr(function());

использовать

std::string function()
{
    std::string someString;
    // some processing!
    return someString;
}

//...

useCharPtr(function().c_str());
1
ответ дан milleniumbug 24 August 2018 в 16:50
поделиться

В C ++ проще всего просто вернуть return std::string (что также эффективно благодаря оптимизации, такой как семантика перемещения RVO и C ++ 11):

std::string returnSomeString()
{
    std::string someString;

    // some processing...

    return someString;
}

Если вы действительно нужен исходный указатель C char*, вы всегда можете вызвать .c_str() в возвращаемом значении, например

// void SomeLegacyFunction(const char * psz)

// .c_str() called on the returned string, to get the 'const char*' 
SomeLegacyFunction( returnSomeString().c_str() );

Если вы действительно хотите вернуть указатель char* из функции, вы можете динамически выделяет строчную память в куче (например, используя new[]) и возвращает указатель на это:

// NOTE: The caller owns the returned pointer, 
// and must free the string using delete[] !!!
const char* returnSomeString()
{
    std::string someString;

    // some processing...

    // Dynamically allocate memory for the returned string
    char* ptr = new char[someString.c_str() + 1]; // +1 for terminating NUL

    // Copy source string in dynamically allocated string buffer
    strcpy(ptr, someString.c_str());

    // Return the pointer to the dynamically allocated buffer
    return ptr;
}

Альтернативой является указание указателя буфера назначения и размер буфера (чтобы избежать переполнения буфера!) в качестве функциональных параметров:

void returnSomeString(char* destination, size_t destinationSize)
{
    std::string someString;

    // some processing...

    // Copy string to destination buffer.
    // Use some safe string copy function to avoid buffer overruns.
    strcpy_s(destination, destinationSize, someString.c_str());
}
10
ответ дан Mr.C64 24 August 2018 в 16:50
поделиться

Вы можете передать указатель на свою строку и напрямую обработать метод (т. е. вообще избегать возвратов)

void returnCharPtr(char* someString)
{    
    // some processing!
    if(someString[0] == 'A')
       someString++;
}
1
ответ дан MrDuk 24 August 2018 в 16:50
поделиться

Если у вас есть свобода изменить возвращаемое значение returnCharPtr, измените его на std::string. Это будет самый чистый метод для возврата строки. Если вы не можете, вам нужно выделить память для возвращаемой строки, скопировать ее с std::string и вернуть указатель на выделенную память. Вы также должны убедиться, что вы удаляете память в вызывающей функции. Поскольку вызывающий абонент будет отвечать за освобождение памяти, я бы изменил возвращаемое значение на char*.

char* returnCharPtr() 
{
    std::string someString;

    // some processing!.

    char* cp = new char[someString.length()+1];
    strcpy(cp, someString.c_str());
    return cp;
}
1
ответ дан R Sahu 24 August 2018 в 16:50
поделиться

Лучшим способом было бы вернуть std::string, который автоматически управляет памятью. Если, с другой стороны, вы действительно возвращали const char*, который указывает на некоторую память, выделенную вами из returnCharPtr, тогда она должна быть явно освобождена кем-то другим.

Оставайтесь с std::string.

1
ответ дан user 24 August 2018 в 16:50
поделиться

Ваши параметры:

Return std::string

Передайте буфер в returnCharPtr(), который будет содержать новый буфер символов. Для этого нужно проверить, что предоставленный буфер достаточно велик для хранения строки.

Создайте новый char массив внутри returnCharPtr(), скопируйте буфер в новый и верните указатель на него. Это требует, чтобы вызывающий ящик явно вызывал delete [] на то, что они явно не создавали с помощью new, или сразу же помещал его в класс интеллектуального указателя. Это решение было бы улучшено, если бы вы вернули умный указатель, но на самом деле имеет смысл возвращать std::string напрямую.

Выберите первый; return std::string. Это, безусловно, упрощенный и безопасный вариант.

1
ответ дан xen-0 24 August 2018 в 16:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: