I need to create an encoding function that receives an original string and a pointer to a result string, encodes the original and stores the encoded string in the result string by pointer
the encoding rules are:
digits are duplicated n 1 times
e.g.: 2 will appear 2 1=3 times in result('2'-->'222')uppercase letters will turn to lowercase and the ASCII value of the lower case will be ordered in reverse and appear in the result str
e.g: 'A' will turn to 'a' whose ASCII is 97 so in the res_str '79' will appearlowercase letters will turn to uppercase letters but in reverse order and their ASCII value will appear also reversed in the res_str
e.g: 'a' will turn to 'Z' whose ASCII value is 90 so in the res_str '09' will appear.
I think I managed to figure out the encoding algorithm but when trying to write to the res_str I go into over flow i don't know if it's the mem allocation or the way i writeto res_str...
int get_codedstring(char *orig_str, char **coded_str)
{
// figuring out the minimal length needed for result_str
int len = 1; // minimal length for string that has nothing in it exept'\0'
int i = 0;
while (orig_str[i] != '\0')
{
if ((int)orig_str[i] >= BOT_DIGIT && (int)orig_str[i] <= TOP_DIGIT) // digit
len = (int)orig_str[i] - BOT_DIGIT 1;
else if ((int)orig_str[i] >= BOT_UPPER && (int)orig_str[i] <= TOP_UPPER) // uppercase
{
if ((int)orig_str[i] >= BOT_LOWER && (int)orig_str[i] <= C)
len = 2;
else
len = 3;
}
else // lowercase
len = 2;
i ;
}
*coded_str = malloc(sizeof(char) * len); // allocating mem for res_str
// encoding
i = 0;
int j = 0;
int temp;
while (orig_str[i] != '\0')
{
if ((int)orig_str[i] >= BOT_DIGIT && (int)orig_str[i] <= TOP_DIGIT) // digit
{
temp = (int)orig_str[i] - BOT_DIGIT 1;
for (j; j < temp; j )
{
*(coded_str[i j]) = orig_str[i];
}
j = i j;
}
else if ((int)orig_str[i] >= BOT_UPPER && (int)orig_str[i] <= TOP_UPPER) // uppercase
{
temp = (int)orig_str[i] 32; // switch to lowercase
// add to coded_str in reverse digit order
if (((int)orig_str[i] 32) >= BOT_LOWER && ((int)orig_str[i] 32) <= C)
{ // a=97,b=98,c=99 the rest need 3 spaces
*coded_str[i j] = (char)(temp % 10) BOT_DIGIT;
j ;
*coded_str[i j] = (char)(temp / 10) BOT_DIGIT;
j ;
}
else
{
*coded_str[i j] = (char)(temp % 100) BOT_DIGIT;
j ;
temp /= 10;
*coded_str[i j] = (char)(temp % 10) BOT_DIGIT;
j ;
*coded_str[i j] = (char)(temp / 10) BOT_DIGIT;
j ;
}
}
else // lowercase
{
temp = (int)orig_str[i] - 32; // switch to lower case
temp = TOP_UPPER - (temp - BOT_UPPER); // reverse order
*coded_str[i j] = (char)(temp % 10) BOT_DIGIT;
j ;
*coded_str[i j] = (char)(temp / 10) BOT_DIGIT;
j ;
}
i ;
}
return len;
}
the defines are:
#define BOT_DIGIT 48
#define TOP_DIGIT 57
#define BOT_UPPER 65
#define TOP_UPPER 90
#define BOT_LOWER 97
#define TOP_LOWER 122
#define C 99
CodePudding user response:
You are dereferencing coded_str
wrong. You are using these which do the same thing according to C Operator Precedence:
*(coded_str[i j])
*coded_str[i j]
But you should dereference coded_str
first, then use the subscript operator:
(*coded_str)[i j]
That is however not the only problem. If calling the function like this:
int main() {
char* encoded;
get_codedstring("Hello world", &encoded);
}
It will calculate len
to be 24
but i j
goes out of bounds with
i(8) j(17) = 25
as can be seen by adding this line before each (*coded_str)[i j]
:
printf("i(%d) j(%d) = %d\n", i, j, i j); fflush(stdout);
This is caused by the algorithm you use to calculate the length being different from the algorithm where you actually populate the resulting array. When you populate the result, you skip one character between each encoded character. The simple solution is to use (*coded_str)[j]
everywhere and not to do j = i j
. Step i
and j
independently and then your calculation will be correct.
You may want to null terminate the result before returning too.
CodePudding user response:
- It is much easier if you use functions. It makes program logic much easier.
- Do not use "magic" numbers. Use C standard functions to determine if char is a digit or upper or lover case letter.
char *addChar(char *str, char c, size_t *size)
{
if(!*size) *size = 1;
str = realloc(str, *size 1);
if(str)
{
str[*size - 1] = c;
str[*size] = 0;
(*size) ;
}
return str;
}
char *charToDec(int c, char *str, size_t *size)
{
for(int mask = 100; mask; mask /= 10)
{
if(mask < 100 || c / mask)
{
str = addChar(str, '0' c / mask, size);
if(!str) break;
c %= mask;
}
}
return str;
}
size_t myfunc(const char *str, char **result)
{
size_t size = 0;
while(*str)
{
if(isdigit((unsigned char)*str))
{
for(int digit = 0; digit < *str - '0' 1; digit )
{
char *tmp = addChar(*result, *str, &size);
if(tmp) *result = tmp;
else {/* error handling */}
}
}
else if(islower(*str))
{
char *tmp = charToDec('Z' - (*str - 'a'), *result, &size);
if(tmp) *result = tmp;
else {/* error handling */}
}
else if(isupper(*str))
{
char *tmp = charToDec(tolower((unsigned char)*str), *result, &size);
if(tmp) *result = tmp;
else {/* error handling */}
}
str ;
}
}
int main(void)
{
char *result = NULL;
myfunc("5aA", &result);
printf("`%s`\n", result);
free(result);
}