C ++에서의 골프 팁


48

C ++에서 골프를 할 때 어떤 일반적인 팁이 있습니까? 저는 C ++에 다소 특정한 코드 골프 문제에 적용될 수있는 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다). 답변 당 하나의 팁을 게시하십시오.


4
C에서 골프를 치기위한 많은 들이 C ++에도 적용되기 때문에 독자들이 그 질문에 익숙하다고 가정하십시오. 유효한 C 골프 팁이 아닌 것을 가지고 있다면 여기에 게시하십시오.
Toby Speight

@TobySpeight 질문 ID 외에 동일한 URL이 있기 때문일 수 있습니다.
NoOneIsHere1

C 및 C ++는 '골프'유형이 아니더라도 옳고 쉽습니다 (C ++의 올바른 하위 집합을 고려하는 경우)
RosLuP

답변:


24

삼항 조건 연산자는 ?:종종 단순한를위한에서 스탠드로 사용할 수 있습니다 if- else상당한 비용 절감에서 문.

다음과 같이 대체 lvalue를 선택하는 데 사용할 수 있다는 점에서 특별한 가치가 있습니다.

#include <iostream>
#include <cstdlib>
int main(int c, char**v){
  int o=0,e=0,u;
  while(--c) ((u=atoi(v[c]))%2?o:e)+=u;
  std::cout << "Sum of odds " << o <<std::endl
            << "Sum of evens " << e <<std::endl;
}

아직 코드를 실행하지는 않았지만 원하는 방식으로 작동하지 않는다고 생각합니다. ((u = atoi (v [c])) % 2? o : e) + = u는 값 o 또는 e를 얻는 왼쪽의 표현식에 값 u를 더하는 것 외에는 변수 o와 e 변경되지 않은 상태로 유지되므로 항상 0이됩니다. 코드를 확인하여 hapens를 확인하십시오. 당신은 그것을 작동하게 주소를 사용해야합니다
Bogdan Alexandru

4
@BogdanAlexandru Er ...해라. 실제로 작동합니다. 괄호 표현식의 값은 e및 중 하나에 대한 참조 o입니다. 이것은이 연산자가 lvalue 일 수 없기 때문에 작동하지 않는 c에서이 연산자의 작동 방식과 다릅니다.
dmckee

5 개의 문자를 절약 std::endl하는 '\n'것으로 교체하십시오
Mukul Kumar

3
@MukulKumar 글쎄요. 그러나 시연의 목적을 위해 팁을 나는 삼항 조건부 명확성을 위해 해제 golfed를 제외한 모든 떠났다.
dmckee

22

정적 저장 기간 변수 (특히 모든 전역 범위 변수를 포함)는 처음에 자동으로 초기화되지 않는다는 사실을 사용하여 두 문자를 저장할 수 있습니다 (보증이없는 자동 변수와는 달리). 그래서 대신

int main()
{
  int a=0;
  // ...
}

당신은 쓸 수 있습니다

int a;
int main()
{
  // ...
}

+1이지만 확실히 나쁜 연습
mondlos

@mondlos : 골프는 기본적으로 나쁜 연습을 의미합니다.
celtschk

15

일부 컴파일러 (예 : GCC)는 다중 문자 상수를 지원 합니다. 큰 정수 값이 필요한 경우 몇 문자를 절약 할 수 있습니다. 예:

int n='  ';

값은 구현별로 다릅니다. 일반적으로의 값 'ab'256*'a'+'b'또는 'a'+256*'b'입니다. 따옴표 사이에 최대 4자를 지정할 수 있습니다.


3
GCC? 당신은 g ++을 의미 합니까?
Nathan Osman

6
@George Edison : GCC는 GNU Compiler Collection의 약자로 C, C ++, Go 등을 포함한 모든 프론트 엔드를 포함합니다.
Joey Adams

@Joey : 알아요.하지만 GNU C 컴파일러의 이름이기도합니다.
Nathan Osman

25
@George : GNU C 컴파일러는 GCC가 아니라 gcc라고합니다.
fredoverflow

기억할 수도 있지만 잊을 수도 있습니다.

12

내가 찾은 것 :

true부울 표현식에서 0이 아닌 값이 평가 되고 부울 x&&yx*y처리 할 때 평가 된다는 사실 활용

(x!=0 && y!=0)

~에 평가하다

(x*y)

아래에서 지적한 것처럼 오버플로를 알아야합니다.


2
기술적으로는 x!=0 && y!=0입니다. 그러나 곱셈을 사용할 때는 오버플로에주의해야합니다. 32 비트 정수를 사용할 때 x = y = 65536 (및 2의 거듭 제곱의 여러 조합)도 x * y = 0이 됩니다.
Martin Ender

네 맞습니다. 여기서는 2 차원 배열 경계 검사로 사용했습니다 : codegolf.stackexchange.com/a/37571/31477 여기서 중요하지 않습니다. 나는에서 그 점을 편집 할 수 있습니다.
Baldrickk

1
그러나 &&단락 동작이 *부족합니다. 예를 들어, 당신은 대체 할 수 없습니다 i++!=0&&j++!=0i++*j++.
celtschk

@celtschk 예, 좋은 지적입니다. 그러나 순전히 부울 대수를 수행하면 작동합니다.
Baldrickk

11

다음 유형을 사용하십시오.

u64, s64, u32, s32 (or int)

반복적 인 단어 / 유형의 경우 다음을 사용하십시오 #defines.

#define a while

while여분의 10자를 보충하기 위해 많이 사용 하는 경우에만 가치가 있습니다 . ( 약 4 )


1
u64, s64, u32 및 s32 유형은 C ++의 일부가 아닙니다. 그것들은 컴파일러의 비표준 확장 일 수 있습니다 (그러나 본 적이 없습니다).
celtschk

5
이 두 가지 팁은 두 가지 답변으로 나뉘어 개별적으로 투표 할 수 있습니다.
trichoplax


10

가능하면, 변경 &&||&|각각.

간단한 if 문을 사용할 때 :

if(<condition>)<stuff>;

다음으로 변경할 수 있습니다.

<condition>?<stuff>:<any single letter variable>;

캐릭터를 저장합니다.


8

사용하는 대신 while(1), 사용을 for(;;)한 문자를 저장 :)


8

절에 둘 이상의 명령문이있는 상황에서 여는 중괄호 대신 쉼표 연산자를 사용하면 몇 개의 문자를 절약 할 수 있습니다.

if(c){x=1;cout<<"Hi";y=2;}else{x=2;cout<<"Bye";y=3;}

vs.

if(c)x=1,cout<<"Hi",y=2;else x=2,cout<<"Bye",y=3;###

일반 IF에 2 개의 문자가 저장되거나 IF / ELSE에 3 개의 문자가 저장되었습니다.

C와 C ++의 구별 점으로 C ++에서 쉼표 식의 결과는 lvalue ... FWIW로 사용될 수 있습니다.


7

배열 요소는 다음과 같은 대신 메모리에 서로 직접 저장되므로 :

for(int x = 0; x < 25; x++) {
    for(int y = 0; y < 25; y++)
        array[x][y] = whatever;
}

다음과 같이 할 수 있습니다 :

int* pointer = array;
for(int i = 0; i < 25*25; i++, pointer++)
    *pointer = whatever;

가독성을 위해 위의 어느 것도 골라 내지 않지만 포인터를 명시 적으로 사용하면 많은 공간을 절약 할 수 있습니다.


공백을 모두 잘라낼 수 있다는 것을 잊지 마십시오! (다른 팁은 있지만 언급해야 함)
stokastic

@stokastic이 예제는 기술을 사용하는 방법을 보여주기 위해 골프 용이 아닙니다.
Stuntddude

6
왜 안돼 for(int* i=array; i<array+25*25; i++)? 그런 다음 하나의 변수 만 추적하면됩니다.
Lucas

6

분명한 것이지만 많은 표준 라이브러리를 사용하고 있으면 using namespace std;몇 문자를 절약 할 수 있습니다.


5
단 하나의 이름 만 사용하지만 자주 사용하는 경우 using std::name;더 짧을 수 있습니다.
celtschk

10
std::5 회 이상 사용하는 경우에만 문자를 저장합니다 .
nyuszika7h

6

a[i]와 동일 하다는 것을 기억하는 것이 유용합니다 *(a+i).

교체 a[0]와 함께 *a두 개의 문자 절감. 또한 a[i][0]동등 *a[i]하고 a[0][i]아래로 축소 i[*a]. 따라서 0배열에서 인덱스를 하드 코딩하는 경우 더 나은 방법이 있습니다.


5

10의 큰 거듭 제곱을 쓰는 대신 e 표기법을 사용하십시오 . 예를 들어, a=1000000000보다 깁니다 a=1e9. a=1e9+24보다 나은 다른 숫자로 확장 할 수 있습니다 a=1000000024.


1
이는 정확히 동일하지 않으므로 사용하기 전에 정수 유형으로 캐스트해야합니다. 예를 들어 1e9/x동일하지 않다 1000000000/x거나 int(1e9)/x.
user202729

5

?:트루 블록에서 표현식없이 삼항 연산자 를 사용할 수 있습니다 (바이트 저장).

#include <iostream>

int foo()
{
    std::cout << "Foo\n";
}

int main()
{
    1?foo():0;  // if (true) foo()
    0?:foo();   // if (!false) foo()
}

여기서 확인하십시오


5
이것은 C ++ 표준이 아닌 GNU 확장으로 보입니다. https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Conditionals.html#Conditionals
ceilingcat

r? foo () : 0; // (r) foo () 이것이 정상이라면 ;;;;;; 하지만이 r? : foo (); 나는 모르겠 음
RosLuP

5

더 짧은 헤더

이것은 GCC에 따라 다르며 다른 컴파일러로 확장 할 수 있습니다.

미리 컴파일 된 헤더

G ++ bits/stdc++.h에서는 미리 컴파일 된 헤더가 다른 모든 헤더로 구성됩니다. import다른 두 가지 가 필요 하면 이것을 사용할 수 있습니다.

더 짧은 헤더.

이것은 http://en.cppreference.com/w/cpp/header에 나열된 모든 헤더입니다 .

길이 순서대로 정렬됩니다.

그들 중 일부는 이미보다 길고 bits/stdc++.h일부는 C ++ 17 지원이 필요합니다. 일부는 TIO G ++에서 지원하지 않습니다 (알지 못하는 이유로). 우리가 가지고있는 걸 걸러 내십시오 :

그들 중 일부는 더 짧은 것으로 대체 될 수 있습니다. 필요한 것을 바꿀 수 있는지 바이너리 검색 만하면됩니다. 특히:

cstdio -> ios        (-3 bytes)
algorithm -> regex   (-4 bytes)
vector -> queue      (-1 byte)
string -> map        (-3 bytes)
bitset -> regex      (-1 byte)
numeric -> random    (-1 byte)

4

#import대신에 #include하나 더 바이트 를 제공합니다.

또한 #import헤더와 공백 사이의 공백 문자 가 반드시 필요한 것은 아닙니다.

#include <map>
// vs
#import<map>

stdlib헤더에서 무언가가 필요한 경우 STL 컨테이너 (바람직한 set또는 map) 대신 헤더를 가져올 수 있습니다 cstdlib.


3

부울에 대한 산술 연산 :

이기는하지만, 비록 일지라도

a*=b>0?.5:-.5

~보다 낫다

if(b>0)a*=.5;else a*=-.5;

그것은만큼 좋지 않다

a*=(b>0)-.5

또한 많이 사용되는 모든 항목에 #define을 사용하십시오. 유형 이름이 필요하지 않기 때문에 종종 함수를 사용하는 것보다 짧습니다.

가능한 많은 것들을 결합하십시오 :

a+=a--;

와 같다

a=2*a-1;

예제는 정확하지만 xlvalue 및 x++rvalue로 사용할 때 정의되지 않은 동작을 호출하도록주의하십시오 . 정의되지 않은 동작 및 시퀀스 포인트
ceilingcat

가능합니다 a + = a--; 정의되지 않은 동작이 있음
RosLuP

3

저렴한 템플릿으로 일반 람다 사용

이외의 유형의 경우 int이를 함수 인수로 사용하면 비용이 많이들 수 있습니다. 그러나 일반적인 람다는 (C ++ 14?) 도입되었으며 람다는 템플릿이 될 수 있습니다- auto인수 유형에 사용 하면 바이트를 절약 할 수 있습니다. 비교:

double f(double x, double y)
[](auto x, auto y)

C ++에서 배열 입력을 받아들이는 아마 가장 좋은 방법입니다 - 일반 람다도 수용 반복자에 매우 편리합니다 [](auto a, auto z), a그리고 z로 전달 begin()하고 end()등 배열 / 벡터 / 목록 /의.


2

작업 "다음 숫자 빼기"에 대한 코드 골프에서의 첫 번째 시도에서 나는 함수 (58 바이트)에서 시작했다.

int f(int N, int P){int F;for(F=N;P;F-=++N,P--);return F;}

그런 다음 람다로 이동하고 초기화를 for(53) 밖으로 이동하여 안전한 5 바이트

[](int N,int P){int F=N;for(;P;F-=++N,P--);return F;}

그리고 마침내에서 for로 전환 한 후 while51 바이트를 얻었습니다.

[](int N,int P){int F=N;while(P--)F-=++N;return F;}

ungolfed 테스트 코드는 다음과 같습니다.

#include <iostream>
int main(void)
{
    int N, P;
    std::cin >> N >> P;
    auto f = [](int N,int P)
    {
        int F = N;
        while (P--)
            F -= ++N;
        return F;
    };
    std::cout << f(N, P) << std::endl;
    return 0;
}

최신 정보:

실제로 for다음과 같은 길이에 도달 할 수 있습니다 while.

[](int N,int P){int F=N;for(;P--;F-=++N);return F;}

2

파티에 늦었을 것 같아요 ...

식 대신 0과 1 대신 -1과 1로 바꾸려면 다음과 같이하십시오.

int x;
if (a * 10 > 5)
    x = 1;
else
    x = -1;

이 작업을 수행:

int x = (a * 10 > 5) * 2 - 1;

사용법에 따라 일부 바이트를 절약 할 수 있습니다.


대신에 int x=(a*10>5)*2-1;, 당신이 할 수없는 int x=a*10>5?1:-1;1 바이트 짧은있는?
girobuz

2

두 개의 정수 변수 a와 b를 바꾸려면

a^=b^=a^=b;

표준 방식보다 5자를 절약하여 사용할 수 있습니다.

a+=b;
b=a-b;
a-=b;

1
그 표준 방법에 대해. ,t이전에 생성 된 정수에서 t=a;a=b;b=t;이미보다 3 바이트 짧았을 것 a+=b;b=a-b;a-=b;입니다. 아직도, 당신 a^=b^=a^=b;은 그것보다 짧아서, +1입니다. 나는 C ++을 모르지만 실제로 작동합니다 . Java 코드 골퍼로서 슬프게도 거기에서 작동하지 않는 것 같습니다 . :(
Kevin Cruijssen

1
@KevinCruijssen 그래, C ++에 대해 언급 했어야했는데, Java를 잘 모르지만 Java a^=b;b^=a;a^=b;에서 잘 작동하고있다.
joker007

1
C ++을 명시 적으로 언급 할 필요가 없습니다. 이 모든 팁은 C ++에 관한 것입니다. :) Java 개발자로서 Java에서 비슷한 작업을 수행 할 수 있는지 궁금하지만 실제로는 그렇지 않습니다. a^=b;b^=a;a^=b;실제로 작동하지만 ,t+ 보다 깁니다 t=a;a=b;b=t;. 여기에 주제가 없기 때문에 Java를 언급하는 것에 대해 죄송합니다. 그러나 C ++ codegolfers에 대한 유용한 팁!
Kevin Cruijssen

2

가져 오는 대신 GCC 내장을 사용하십시오.

당신이 GCC 컴파일러를 사용하는 경우, 때로는 같은 자신의 내장 기능을 사용하는 데 도움이 __builtin_puts또는 __builtin_clz. 예를 들어

44 바이트 :

int main(){__builtin_puts("Hello, world!");}`

50 바이트 :

#import<cstdio>
int main(){puts("Hello, world!");}

1

C ++ 11 이상 (지금은 항상 그래야 함)을 수행하는 auto경우 가능하면 복잡한 유형에 사용하십시오.

예 : 66이 아닌 54 바이트

#include<vector>
std::vector<int> f(std::vector<int> l){return l;}
#include<vector>
auto f(std::vector<int> l){return l;}

또한 성능이 중요하지 않기 때문에 일부 문제의 std::list경우 몇 바이트 미만으로 작업을 수행 할 수 있습니다.

#include<list>
auto f(std::list<int> l){return l;}

1

함수는 <algorithm>종종 a.begin(),a.end()정말로 긴 것을 전달해야하지만 대신 is 또는 인 &a[0],&*end(a)경우 3 바이트를 절약 하는 데 사용할 수 있습니다 .avectorstring

sort(a.begin(),a.end());
sort(begin(a),end(a));
sort(&a[0],&*end(a));

0

사용하지 마십시오 string(""), 사용 "". 8 바이트를 절약합니다.


정확히 동일하지 않습니다. 예를 들어 "" + 'a'char* + char반면, 포인터 또한 인 std::string("") + 'a'이다 std::string + char- 문자열 연결. string()작동 할 것이다.
user202729
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.