An easy fix could be to define an additional route without the offset parameter:
return array(
'articles/(?P<sectionId>\d+)' => 'articles/index',
'articles/(?P<sectionId>\d+)/(?P<offset>\d+)' => 'articles/index',
);
In your template, you'd need to check if the offset parameter is defined, and if not, set it to 0:
{{ offset | default( 0 ) }}
or
{% set offset = offset is defined ? offset : 0 %}
EDIT:
Another way to solve this is by making the offset segment capturing group optional, as per @carlcs' answer to this question – in my opinion this is a bit more elegant than having two different routes:
return array(
'articles/(?P<sectionId>\d+)(/(?P<offset>\d+))?' => 'articles/index',
);
The trick here is wrapping the last segment in parentheses, appending a question mark at the end.