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&&y을 x*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++!=0와 i++*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.