In function, you are using the next snippet of code
for (i = 0, j = 0; s1[i] != '\0'; i++, j++) {
if (s1[i] == '-' && s1[i-1] != ' ' && s1[i+1] != ' ') {
If you are going to do something with s1[i-1]
, then i
cannot go from 0
, or you'll be checking s1[-1]
in first loop iteration, which is out of array bounds. This is an error, that produces Undefined Behaviour. An alternative would be to begin at i = 1
, or to check if strcmp(s1 + i, " - ") == 0
, which never checks before i
or never goes after a \0
.
for (i = 0, j = 0; s1[i] != '\0'; i++, j++) {
if (strcmp(s1 + i, " - ") == 0) {
(but it is possible that this is not what you are looking for, while checking that the character at i
is -
and the character at i-1
is a space, and the character at i+1
is another space is somehow equivalent as checking if the character sequence at i
---well, not at i-1
--- is the sequence -
)
The problem in your code is that you need a buffer to copy the strings... as when you say something like: a-z
, then that spans a string longer than the original a-z
sequence. First of all, you must recognize the subsequence of two chars (which can or cannot be the -
char) and a -
in the middle. This is something you can do with this state machine:
/* expand.c -- expands ranges in the form a-b
* Date: Fri Dec 20 08:02:30 EET 2019
*/
#include <stdio.h>
#define ERR_ENOSPACE (-1)
#define ERR_ERANGE (-2)
ssize_t expand(
char *source, /* the source string */
char *target, /* the target string */
size_t target_length) /* the target length */
{
int ch, /* the character to copy */
first_char, /* first char in range */
last_char; /* last char in range */
size_t len = 0; /* the length of the complete range string */
ssize_t result = 0; /* the length returned */
while((ch = *source++) != 0) { /* s is the input string */
switch (len) { /* length of substring (or machine state). */
case 0:
first_char = ch; /* annotate first char */
len = 1; /* state is now 1 */
break;
case 1: switch (ch) {
case '-': /* valid range go to state 2 */
len = 2;
break;
default: /* not a valid range, store a new first char
and remain in this state. And copy the last
char to the output string. */
if (target_length < 3) {
/* not enough space (3 is needed for first_char,
* this char and the final \0 char) */
return ERR_ENOSPACE;
}
*target++ = first_char; target_length--;
first_char = ch; /* len = 1; */
result++;
} break;
case 2:
last_char = ch; /* we completed a range */
if (first_char > last_char)
return ERR_ERANGE;
ssize_t n = last_char - first_char + 1; /* number of output chars */
if (n + 1 > target_length) {
/* we need space for n characters, * plus a '\0' char */
return ERR_ENOSPACE;
}
/* copy the string */
while (first_char <= last_char)
*target++ = first_char++;
target_length -= n;
result += n;
len = 0; /* state comes back to 0 */
break;
} /* switch (l) */
} /* while */
/* check state on end. */
switch (len) { /* depending on length we need to add a partial
built sequence */
case 0: break; /* nothing to append */
case 1: /* we have a spare first_char, add it */
if (target_length < 2)
return ERR_ENOSPACE;
*target++ = first_char; target_length--;
result++;
break;
case 2: if (target_length < 3)
return ERR_ENOSPACE;
*target++ = first_char; *target++ = '-';
target_length -= 2; result += 2;
break;
}
/* now fill the final \0 */
if (target_length < 1) {
return ERR_ENOSPACE;
}
*target = '\0';
return result;
} /* expand */
int main()
{
char line[1024];
char outbuf[8192];
while (fgets(line, sizeof line, stdin)) {
ssize_t n = expand(line, outbuf, sizeof outbuf);
#define CASE(err) case err: fprintf(stderr, "ERROR: " #err "\n"); break;
switch(n) {
CASE(ERR_ENOSPACE)
CASE(ERR_ERANGE)
default: printf("OUTPUT: %s\n", outbuf); break;
} /* switch */
} /* while */
} /* main */
The sample code is a full sample (with a main()
routine) you can compile and test.