{ }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()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 2개 언어 풀이

이 문제는 C·C++만 받아요.
메모리를 직접 빌리고 돌려주는 일은 두 언어의 몫이고, Python·JavaScript·TypeScript·Java·C#·크레이콘은 목록이 알아서 늘어나고 가비지 컬렉터가 치워 줘서 쓸 일이 없어요.
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;}