Tips for golfing in C
C is a language I use most apart from Python and as someone who likes code golf challenges, what tips are there to golf in C?
Use pointer arithmetic and `\0 …
3y ago
For the sake of code golf, you …
3y ago
Assign `int`s before `main(){} …
3y ago
Abuse (as few) libraries (as p …
3y ago
4 answers
Abuse (as few) libraries (as possible)
We don't want to use too much libraries when playing challenges. Sometimes, libraries aren't used at all in some answers in C.
What if we want to shorten some code? Functions do the trick, specifically built-ins. It's specified you don't have to apply the byte count from accessing libraries, and with this in our advantage, we can use libraries, but it's better if we use only 1 or a few.
0 comment threads
Use pointer arithmetic and \0
with string literals
In C, strings are just zero-terminated character arrays, which means you can play tricks with pointer arithmetic. For example, the line
char*s=a<2?"":"s";
can be replaced with
char*s="s"+(a<2);
Note that you also can use zero bytes inside string constants, which may also help saving a few bytes. For example, if n
is a number from 0 to 3, instead of:
char*s[]={"zero","one","two","three"};puts(s[n]);
you can write
char*s="zero\0.one\0..two\0..three";puts(s+6*n);
Note that the dots are just dummy characters so that the actual strings start at multiples of 6 characters. One may get rid of them at the cost of more complicated arithmetic:
char*s="zero\0one\0two\0three";puts(s+4*n+!!n);
Whether you save more characters in the string literal than adding to the expression of course depends on the specific strings (and on how often you use that expression in the code).
Note also that if it is the only use of s
, you may shorten the code further, since unlike array definitions, string literals can be used inline:
puts("zero\0one\0two\0three"+4*n+!!n);
0 comment threads
Assign int
s before main(){}
This is a combination of 2 golfing tricks. It's possible to write a program as just main(){}
, though it will send a warning, not an error though, so it's still safe to run.
A cool trick with using this is assigning values meant to be int
s which you can assign inside main
anyway.
Try changing the number value here, it works!
i;main(){i=0;printf("%i",i);}
For the sake of code golf, you first need to decide if you wish to compete in strictly conforming ("real") C, in which case you can't rely on non-standard extensions, poorly-defined behavior or obsolete features.
Or you can compete in non-standard extensions (gcc/GNU etc), when whatever binary the compiler lets through with default settings is fair game - including those that may be abusing poorly-defined behavior.
List of tricks below:
-
Format of
main()
In strictly conforming hosted C, the formint main()
is the most compact. Empty parenthesis is obsolete style but it has not yet been formally withdrawn. Alternatively two parameters can be used, normally named argv and argc though C allows us to rename them. In conforming C, we may not change their types however, so the most compact conforming version is:int main(int c,char**v)
(Or use compatible types.)
main(c,v)
is however not conforming.In conforming freestanding C, other forms of main() may be used, but that's for embedded systems and not likely applicable for code golf.
In non-conforming/gcc extensions, old C90 style
main()
works.Note that
return 0;
is no longer necessary in main() as from C99 - omitting it is well-defined. -
Format of functions. Non-conforming K&R style functions are still supported by most compilers, for example:
f(a,b)int a;char b;
This can be handy when you need to declare parameters and local variables with the same type.
-
Abuse static storage duration. Variables declared at file scope have static storage duration and are therefore guaranteed by the standard to be zero-initialized, saving the need to do such in code.
-
Abuse C90 implicit int. In C90 and non-conforming gcc extensions you can declare a variable as
x;
and you get anint
. Similarly, in C90 functions that declare no return type were assumed to returnint
. -
Omit include files. While not allowed in strict C, non-standard gcc allows to omit all
#include
. -
Always use for loops.
for(;;)
is the most compact form. The first clause can be used for variable declarations, which is handy since you have to leave a semicolon there anyway. The 2nd and 3rd clauses can contain pretty much any code, such as a long list separated by,
operator. In many cases you can place the whole program there and then end the line with;
, no need for a loop body with{}
. -
Use recursion instead of loops. Recursion can save a lot of overhead code, in case the equivalent loop has a suitable exit condition that needs to be there no matter.
-
Use
?:
instead of if-else. It is far more compact and can be used to write long nested expressions in compact ways. -
&& short circuit instead of if. For example
if(foo)bar();
can often be written asfoo&&bar();
. -
Mix ++ and -- with other expressions. Contrary to good programming practice, this can save characters. For example
for(;;i--)printf("%d",a[i]);
could be written asfor(;;)printf("%d",a[i--]);
. Experiment with prefix and postfix versions too. Big chance that you end up with a non-conforming solution though. -
!
is generally handy, for example when converting a non-zero value to 1, or to get boolean 1/0 out of expressions. -
Use bitwise operators when possible.
&&
and||
can sometimes be replaced with&
and|
. -
^
xor instead of!=
. -
sizeof
doesn't need parenthesis if the operand is an expression. Don't dosizeof(expr)
, always dosizeof expr
. -
Pointer arithmetic instead of array indexing.
arr+n
notarr[n]
. -
Use
#
pre-processor stringification. If you can afford a#define
then everything inside it can be turned to string literals, which is handy if you have to repeat a lot of strings. Pre-processor string concatenation is also handy:"foo" "bar"
will create "foobar". -
int
can often be used instead ofchar
for storing characters. -
Integer constants are more effective than character ones. Use
char ch=32;
notchar ch=' '
. -
Use binary arithmetic instead of larger numbers.
~0
instead of4294967296
.1<<30
instead of 0x40000000. And so on. -
X-macros are handy for avoiding repetition. Particularly when listing data. One example here: https://codegolf.codidact.com/posts/279820/279856#answer-279856
-
Abuse the poor type system and endianess when printing strings. Wildly non-conforming:
int x=65; puts(&x);
This prints the null terminated string"A"
, since puts treats the raw binary on a 32 bit int little endian machine as hex41 00 00 00
. This can also be handy for integer to string conversions where you already have the integer in memory. -
Use
puts when possible
. It is compact and saves you from printf with the burdensome format string. It also prints new line implicitly. And I've seen some other clever uses likemalloc(puts(s))
instead ofmalloc(strlen(s)+1)
. -
Use VLA. Avoid malloc, use VLA instead.
int x[n];
beatsint*x=malloc(n);
-
Use evil non-standard libs. Some compilers support
gets
,putch
and similar compact functions as non-standard extensions without the need to include special headers.
0 comment threads