{ }codelper
動的メモリP0075

単語をためておく

一行目に単語の数 n が与えられ、続く n 行に単語が一つずつ与えられる。
単語は英小文字だけでできている。
一行目には単語を入力の逆の順に空白一つで区切って出力し、二行目にはいちばん長い単語を出力せよ。
いちばん長い単語が複数あれば、入力でいちばん前に出たものを出力する。
n は実行してみるまでわからないので、大きさを決めた配列ではなく実行中に確保したメモリに単語をすべて入れておいて解いてみよう(C は malloc・free、C++ は std::vector と std::string)。

入力
1 ≤ n ≤ 2,000、単語の長さは 1 以上 100 以下
出力
二行:逆に並べた単語、いちばん長い単語
例 1 · stdin
4
hi
hello
hey
howdy
stdout
howdy hey hello hi
hello
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 2 言語の解答

この問題は C・C++ だけを受け付けます。
メモリを自分で確保して返すのはこの二つの仕事で、Python・JavaScript・TypeScript・Java・C#・Craykon はリストが勝手に伸び、ガベージコレクタが片づけてくれるので書くことはありません。
C は二回確保します。
単語を指すポインタの枠 char **words = malloc(n * sizeof *words) と、単語ごとに malloc(strlen(buf) + 1)(+1 は終わりを示す '\0' の分)にコピーします。
使い終わったら単語を一つずつ free してから free(words) と、確保した分をちょうど一回ずつ返します。
C++ は std::vector<std::string> が確保も解放も引き受けます(RAII)。
落とし穴二つ:① C で scanf("%100s", buf); words[i] = buf; のようにコピーせずアドレスだけ入れると、すべての枠が同じ buf を指し、全部が最後の単語に見えます。
エラーは出ません。
② C++ の std::vector<std::string> words(n); はすでに空の文字列 n 個が入った vector なので、そこに push_back するとその後ろに付いて大きさが 2n になります。
枠だけ確保するなら reserve(n) のあと push_back、そうでなければ words(n) のあと words[i] = w です。

C++main.cpp · 26 行
#include <iostream>#include <string>#include <vector> int main() {    std::ios::sync_with_stdio(false);    std::cin.tie(nullptr);    int n;    std::cin >> n;     // vector와 string이 알아서 힙 메모리를 빌리고, 범위를 벗어나면 돌려준다(RAII)    std::vector<std::string> words;    words.reserve(n);  // 칸을 미리 잡아 둘 뿐, 크기(size)는 아직 0    for (int i = 0; i < n; i++) {        std::string w;        std::cin >> w;        words.push_back(w);  // string은 대입·push_back 때 글자를 복사해 둔다    }     for (int i = n - 1; i >= 0; i--) std::cout << words[i] << (i > 0 ? ' ' : '\n');     const std::string* best = &words[0];    for (const auto& w : words)        if (w.size() > best->size()) best = &w;    std::cout << *best << "\n";}
Cmain.c · 33 行
#include <stdio.h>#include <stdlib.h>#include <string.h> int main(void) {    int n;    scanf("%d", &n);     /* 낱말 수는 실행해 봐야 안다: 낱말을 가리킬 포인터 n칸을 힙에서 빌린다 */    char **words = malloc(n * sizeof *words);    if (words == NULL) return 1;     char buf[101];  /* 읽기용 칸은 하나뿐이라, 낱말마다 따로 복사해 둬야 한다 */    for (int i = 0; i < n; i++) {        scanf("%100s", buf);        size_t len = strlen(buf);        words[i] = malloc(len + 1);  /* +1은 끝을 알리는 '\0' 자리 */        if (words[i] == NULL) return 1;        memcpy(words[i], buf, len + 1);    }     for (int i = n - 1; i >= 0; i--) printf("%s%c", words[i], i > 0 ? ' ' : '\n');     const char *best = words[0];    for (int i = 1; i < n; i++)        if (strlen(words[i]) > strlen(best)) best = words[i];    printf("%s\n", best);     /* 빌린 것은 빌린 만큼 돌려준다: 낱말 하나하나, 그다음 포인터 칸 */    for (int i = 0; i < n; i++) free(words[i]);    free(words);    return 0;}