質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.01%

  • C++

    2929questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Visual Studio

    1490questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • VC++

    125questions

    VC++ (Visual C++) とは、Microsoft製のC++のための統合開発環境です。

配列を返す関数を作りたい[VC++][VS2008]

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 237

notgoodpg

score 18

前提・実現したいこと

配列を返す関数を作りたい。
戻り値に配列の長さ、引数にポインタをもつ関数で配列の値が取得できるようにしたい。
具体的には、ポインタ引数を関数内でnewし、memcpyで値を書き込んだら
関数の外でポインタを参照することで値を参照したい。
このサイトのGetReceive関数を参考にしています。

よろしくお願いいたします。

発生している問題・エラーメッセージ

配列のポインタを指定したつもりのポインタが未定義のままになっており値を参照できない。 // ご指摘により解決しました
memcpyによりdstに対してnewした領域にsrcの持っていた値がコピーされ、srcをdeleteしたところでdstにはすべての文字がコピーされ保持されると思っていました。
しかし、関数内でsrcをdeleteしたことによってdstから参照する文字の一部が破壊されてしまいます。
srcからコピーした文字をdstからすべて参照する方法は無いでしょうか?
(最初の質問で文章にし忘れていました。申し訳ございません)

該当のソースコード

#include <iostream>

using namespace System;

char* m_src;

void IniSrc()
{
    m_src = new char[16];
    char temp[16] = { 'W','e','a', 'r', 'e', 't', 'h', 'e', 'D', 'i', 'v', 'i', 's', 'i', 'o', 'n' };
    memcpy( m_src, temp, sizeof(temp));
}
// うまく動作しない関数
//int MemCpyTest(char* dst) ご指摘を受けて修正
int MemCpyTest(char*& dst)
{
    const int strLen = 16;
    dst = new char[16];

    // memcpy(dst, m_src, sizeof(m_src)); ご指摘を受けて修正
    memcpy(dst, m_src, strLen);

    delete[] m_src; // いわゆる読み捨てのような事を行いたいのでここでm_srcをdeleteしてしまいたい

    return strLen;
}

int main()
{
    char *str = NULL; 

    IniSrc();
    int strLen = MemCpyTest(str); // newで確保した領域の先頭アドレスをstrに渡す事に成功しました

    for (int i = 0; i < strLen; ++i) { // 解決 // しかしmemcpyではsrcをdeleteしたことによって値が破壊され
        std::cout << str[i]; // 解決 // 値の一部が変わってしまいました
    }

    std::cout << std::endl;

    std::cin;

    delete [] str; // ご指摘を受けて追加

    return 0;
}

補足情報(言語/FW/ツール等のバージョンなど)

  • Windows7/64bit SP1
  • VisualStudio2008
  • VC++
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+6

これでいいのかな?

#include <iostream>

char* m_src;

void IniSrc() {
  m_src = new char[16];
  char temp[16] = { 'W','e','a', 'r', 'e', 't', 'h', 'e', 'D', 'i', 'v', 'i', 's', 'i', 'o', 'n' };
  memcpy( m_src, temp, sizeof(temp));
}

int MemCpyTest(char*& dst) { // 引数はポインタの'参照'な!
  int strLen = 16;
  dst = new char[strLen];
  memcpy(dst, m_src, strLen);
  return strLen;
}

int main() {
  char *str = NULL;

  IniSrc();
  int strLen = MemCpyTest(str);

  for (int i = 0; i < strLen; ++i) {
    std::cout << str[i];
  }
  std::cout << std::endl;
  delete[] str; // 捨てるのは使ったあとぢゃないと。
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/18 16:23 編集

    ご回答ありがとうございます。
    引数をポインタ引数の参照渡しに変更したらnewすることで確保した領域の先頭アドレスを関数の外でも参照できるようになるのですね。

    キャンセル

  • 2018/01/18 16:38

    >> 引数をポインタ引数の参照渡しに変更したらnewすることで確保した領...

    そんな小難しい話というよりは
    ただ単に質問者さんは
    void hoge(int a){a = 1;}
    に対して、引数で渡した変数が変わらない!なんで?とやっていただけです。

    キャンセル

  • 2018/01/18 16:49

    ありがとうございます。
    その通りですね。

    キャンセル

  • 2018/01/18 17:01 編集

    ま、そーゆーことで。
    僕ならvector<char> 返すけどねー
    vector<char> str = MemCpyTest();
    const char* ptr = str.data(); // 先頭位置
    int len = str.size(); // 大きさ
    これなら使った後でdelete[]せんでえぇし。

    キャンセル

  • 2018/01/18 17:04

    ありがとうございます。
    改善に役立てさせていただきます。

    キャンセル

  • 2018/01/18 17:16 編集

    さもなくば unique_ptr<char>/shared_ptr<char> こいつも自動的に解放してくれる。

    キャンセル

  • 2018/01/19 09:07

    有益な情報をありがとうございます。
    スマートクラスというもののようですね初めて知りました。
    内容について調べてよりよい実装を模索してみます

    キャンセル

  • 2018/01/19 09:29

    "スマートポインタ(賢いポインタ)"な。
    でもなー...VS2008じゃなー...

    キャンセル

+4

引数(char* dst)を使う前に、書き換えているところが問題です(下記のコードの最後の行で、引数 dst の値が変更されています)。

”   dst = new char[16];”の行は不要なのではないでしょうか。

// うまく動作しない関数
int MemCpyTest(char* dst)
{
    const int strLen = 16;
    dst = new char[16];

また、C/C++言語の文字列は、末尾に"\0"が付いている必要があります。そのため、16文字のASCII文字列を表すには17バイトのメモリが必要です。
最初から最後までサイズが16のcharの配列として扱うのなら良いのですが、”char* dst”のように文字列として扱っている箇所が散見されるので、思ったように動作しない可能性があります(最悪の場合、文字列の最後を見つけようとして、アクセスが許されないメモリ領域に達し、Segmentation Fault等のシステムエラーを引き起こします)

この観点からも、コードを見直してください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/18 16:42

    ご回答ありがとうございます。
    > ” dst = new char[16];”の行は不要なのではないでしょうか。
    領域を動的に確保したいのでこのように書いています。
    領域を確保せずにmemcpyしたらエラーになると思うのですが、どうでしょう
    (単純にこの行を削除して動かしたらエラーが発生しました。)
    >また、C/C++言語の文字列は、末尾に"\0"が付いている必要があります。そのため、16文字のASCII文字列を表すには17バイトのメモリが必要です。
    > 最初から最後までサイズが16のcharの配列として扱うのなら良いのですが
    ご指摘ありがとうございます。
    ですが、この場では単純に16文字のchar配列と捉えていただきたいです。

    キャンセル

+3

しかし、関数内でsrcをdeleteしたことによってdstから参照する文字の一部が破壊されてしまいます。

それが原因ではありません。

epistemeさんの回答memcpy(dst, m_src, strLen);
ご自身のコードmemcpy(dst, m_src, sizeof(m_src));
をよく見比べてみてください。
さらにsizeof(m_src)がいくつになるか確認してみてください。

m_srcchar*型変数なのでsizeofの結果は格納されている文字数に関係なく4や8などの固定値をとります。
つまりmemcpy(dst, m_src, sizeof(m_src));では、m_srcの前半部分しかdstにコピーできていません。
その結果、呼出元での16回のループ後半では、newで確保されたdstの未初期化の値を出力しているため、破壊されているように見えているだけです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/18 16:58

    ご回答ありがとうございます。
    せっかく頂いた回答なのに重要な箇所を見落としていたわけですね・・・ご指摘ありがとうございました。

    キャンセル

+2

vector<char> を返してみた(ただしC++11)

#include <iostream>
#include <vector>

char* m_src;

void IniSrc() {
  m_src = new char[16];
  char temp[16] = { 'W','e','a', 'r', 'e', 't', 'h', 'e', 'D', 'i', 'v', 'i', 's', 'i', 'o', 'n' };
  memcpy( m_src, temp, sizeof(temp));
}

std::vector<char> MemCpyTest() {
  return std::vector<char>(m_src, m_src+16);
}

int main() {
  IniSrc();
  std::vector<char> str = MemCpyTest();

  for ( char ch : str ) {
    std::cout << ch;
  }
  std::cout << std::endl;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/22 09:32

    ご回答ありがとうございます。
    かなり簡潔で読みやすくなりますね。コードの改善の参考にさせていただきます。

    キャンセル

0

もう解決していますが、C++ならstringを使っても良いような・・・。
趣旨がよくわからなかったのですがメモリのコピーをしたいのでしょうか?
単純に移動をしたいのであればunique_ptrを使っても良いような気がします。

#include <iostream>
#include <malloc.h>
#include <memory>

using uPtrChar = std::unique_ptr<char>;
uPtrChar m_src=nullptr;

void IniSrc()
{
    char temp[17] = { 'W','e','a', 'r', 'e', 't', 'h', 'e', 'D', 'i', 'v', 'i', 's', 'i', 'o', 'n','\0' };
    m_src.reset(new char[sizeof(temp)]);
    memcpy(m_src.get(), temp, sizeof(temp));
}

int MemCpyTest(uPtrChar& dst)
{
    const int strLen = 17;
    dst.reset(new char[17]);
    //memcpy(dst.get(), m_src.get(), strLen);
    //m_src.release();
    dst = std::move(m_src);    //こっちでも良い
    return strLen;
}

int main()
{
    uPtrChar str = nullptr;

    IniSrc();
    int strLen = MemCpyTest(str); 

    for (int i = 0; i < strLen; ++i) { 
        std::cout << str.get()[i]; 
    }

    std::cout << std::endl;
    char temp;
    std::cin>>temp;
    return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/18 17:42

    書いたあとに気がついだんですがVS2008なんですね。。。多分2010からじゃないとこのコード使えないです。参考までに。

    キャンセル

  • 2018/01/22 11:03 編集

    ご回答ありがとうございます。
    VS2010以降ならば右辺値を破棄する処理が行えるのですね。勉強になりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 91.01%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    参照型?ポインタ?

    関数の引数が書きなのですが、 通常のポインタや参照型と何が違うのでしょうか? , char*& strResult,

  • 解決済

    unique_ptrで確保した領域を外部関数へ渡す方法をご教授お願いします

     unique_ptrを以下のような外部関数へ直接渡す方法を知りたいです。 unique_ptr型から生ポインタを引数としている関数を呼び出したかったのですが、getメソッドを使

  • 解決済

    malloc関数、文字化け

    Windows で実験コードを作成していたら、表示がおかしくなりました。 #include<stdio.h> #include<stdlib.h> #include <str

  • 解決済

    char型の配列変数にchar型の変数を代入したい

    使用言語 C 環境 Visual Studio 2017 初めての質問です。 独学でプログラミングを始めたのですがわからないところがあり困っています。 char型の配列変数の使い方

  • 受付中

    c言語 文字列を逆順にして出力する

    発生している問題・エラーメッセージ 文字列を逆順にする関数を作成したのですが最後の文字の入れ替えができません。少しいじるとコアダンプと出てしまいます。どなたか解決法を教えてください

  • 解決済

    C++の回数を指定しない文字列の入力処理について

    タイトルの付け方が下手でごめんなさい。 C++の入力処理で、回数を指定しない文字列の入力処理はどのように実装すればよいのでしょうか。例えば、 int n; char str[1

  • 解決済

    Cの配列を逆順にしたい

    Cで書かれたコードを編集して出力されるデータの配列を逆順にしたいです。 具体的なコードは下記に置いてあります。 https://github.com/namuyan/yescr

  • 解決済

    マルチバイト文字のchar*をvector<char*>に変換したい

     前提・実現したいこと マルチバイト文字が格納されているchar*型の文字列をvector<char*>に変換したいです。 char* String = "abcあいうえお"

同じタグがついた質問を見る

  • C++

    2929questions

    C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

  • Visual Studio

    1490questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • VC++

    125questions

    VC++ (Visual C++) とは、Microsoft製のC++のための統合開発環境です。