Fixing small error in output using arrays in C - c

I am currently working on a project that when given a main function which calls another function confab(), outputs a serious of characters. The question refers to some made up race. They choose an integer nRows between 2 and half the length of the message, e.g. a message of length 11 would allow values of nRows in the range 2 to 5. The message is then written down the columns of a grid, one character in each grid cell, nRows in each column, until all message characters have been used. This may result in the last column being only partially filled. The message is then read out row-wise.
For example the message "Don't wait until the last day before starting" with a nRows of 3 would return:
D'wtnlhltabo ai.ota t ea yersrnn iuit sd fettg
I have written code that does this fairly efficiently, however I have been provided with a test case that i cannot seem to work out.
char buffer[8] = {'*','*','*','*','*','*','*','*',};
confab("ABCDEF.", 3, buffer);
printf("%s\n", buffer);
Is this example, and the output it should give is:
AD.BECF
However my code returns:
AD.BECF*
Due to the extra * in the outText buffer not being replaced with a character. I have tried many things such as removing this extra *, or re initializing the outText to be the same length as the inText (within the code as the main case provided is not allowed to be edited), however nothing thus far has made a difference.
I was wondering if there would be a quick edit I could apply to my code that would perform this change, as I cannot seem to find a way apart from editing the main input which is not allowed.
My code is as follows:
/*
* Confabulons.c
* A program to encode for the Confabulons
*
* August 8th 2015
*/
#include <stdio.h>
#include <string.h>
//A simple function confab which given input text, and a number
//of rows, returns a phrase in the Confabulons encoding scheme.
void confab(const char inText[], int nRows, char outText[])
{
int count = 0;
int i = 0;
int z = 0;
int len = strlen(inText);
while (z < nRows)
{
while (((int)inText[count] > 0) && (count < len))
{
outText[i] = inText[count];
i ++;
count = count + nRows;
}
z ++;
count = z;
}
}

At the end of the function add line:
outText[i] = '\0';

You need to validate the length of the outText string, try:
void confab(const char inText[], int nRows, char outText[])
{
int count = 0;
int i = 0;
int z = 0;
int len = strlen(inText);
int lenOut = strlen(outText);
while (z < nRows)
{
while (((int)inText[count] > 0) && (count < len))
{
outText[i] = inText[count];
i ++;
count = count + nRows;
}
z ++;
count = z;
}
if (i < lenOut) {
outText[i] = '\0';
}
}

Related

How to return a matrix of all occurrences of given word/pattern?

I am trying to implement a function that's called Sniffer which gets two inputs and returns the correspond matrix.
First input is an integer binary array values (just zeros or ones)
second input is your searched word ( the word you choose it as argument to your function )
The functionally of the function :
Searching for occurrence of the given word within your given binary array.
At each occurrence of your word there's always follows 8 bits following it, assume that always the input is correct (it means that there's no possibility two occurrence occur one after the other without at least there's space 8bits (8 binary values)!).
Then the function must return a matrix(integer matrix) of those followed 8bit for each occurrence of the word sorted corresponded by every row of the matrix. (the functions returns just the first 8bit followed each occurrence of the Searched word)
This means:
First row has first 8 followed bit on first occurrence of the word.
Second row has first 8 followed bit on second occurrence of the word.
Third row has first 8 followed bit on third occurrence of the word.
Fourth row has first 8 followed bit on fourth occurrence of the word.
etc ...
I will elaborate by examples:
function structure is
Code:
int ** SnifferPattern(int* givenArray , int* SearchedWord);
//it returns the corresponded matrix so used int** ;
example 1:
givenArray = {1,0,1,0,1,1,1,1,1,1,1,1,0,0};
SearchedWord = {1,0,1,0};
so the function returns a matrix(size 1x8 - 8 corresponds to 8followed bit)
the first row is {1,1,1,1,1,1,1,1}, which is the first 8 bit followed
the word 1010 the matrix here with one row because there's just
one occurrence of the `SearchedWord` in the given array.
example 2:
givenArray = {1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,0,1,0,1,0};
SearchedWord = {1,1,0,0}
so the function returns a matrix the first row is {1,1,1,1,1,1,1,1}
which is the first 8 bit followed the word 1010 for the first occurrence.
for the second occurrence we see the word appear , so the second row of
the returned matrix(size 2x8) will include the first 8bit followed the
word 1010 of the second occurrence. so second row of the matrix
is {1,0,1,0,1,0,1,0} so the returned matrix (size 2x8) has two rows
(because there's two occurrences of the SearchedWord) which each row
corresponds to each occurrence of the SearchedWord.
example 3:
givenArray = {1,1,1,0,1,1,1,1,1,1,1,1,0,0};
SearchedWord = {0,1,0}
so the function returns a matrix zero row (like an array with zero values)
size 1x8 (8 columns is corresponded to 8followed bit). There's no
occurrence of the SearchedWord within the givenArray so we return a zero
matrix. There's no overlap between the occurrences of the searchedWords ,
so we assume always correctness of input.
I will explain my algorithm (a pleasure if there's another suggestions more compatible to my case)
My algorithm is searching for the word at every occurrence and then take at every occurrence the first followed 8bit. I take them and store them in a matrix's rows. But it sounds much hard to complete with this.
what I succeeded / tried to implement in C is this:
int ** SnifferPattern(int* s ; int* w)
{
// s is the given array, w is the searched Word , number occurrences
// here 2 , so it should be two prints on the output of the program.
int n;
int a[1000];
int i=0;
int j;
int k = 0;
int l;
int found = 0;
int t = 0;
a[k++] = i;
j = 0;
for (i = 0; i < k; i++)
{
n = a[i] - j;
if (n == (sizeof(w)/sizeof(w[0])))
{
t = 0;
for (l = 0; w[l]; l++)
{
if (s[l + j] == w[l])
{
t++; // Matched a character.
}
}
if (t == (sizeof(w)/sizeof(w[0])))
{
found++; // We found a match!
printf("word occurred at location=%d \n", j); // Pint location
}
}
j = a[i] + 1;
}
}
int main() {
int s[1000] = {1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1};
int w[1000] = {1,0,1};
// s is the given array, w is the searched Word , number occurrences
// here 2 , so it should be two prints on the output of the program.
SnifferPattern(s , w)
//I should print all the matrix's row in the main function .
return 0;
}
I think I have figured out what you need. And, as stated in your question ("at each occurrence of your word there's always follows 8 bits"), the following requires that a least 8-integers follow any match of w in s. Since you will include 8-integers in each row of the matrix you return, then using a pointer-to-array-of int[8] allows a single free() of the result in the caller.
Your sniffer function will loop over each integer in s keeping a counter index (ndx) of each time an integer in w matches the integer in s. When ndx equals the number of elements in w a match has been found and the next 8 integers are are collected as the columns in that row of your matrix using next8 as the index. You could write your sniffer function as:
#define AFTER 8
/* function returning allocated pointer to array of 8 int, *n of them */
int (*sniffer (int *s, int selem, int *w, int welem, int *n))[AFTER]
{
int ndx = 0, /* match index */
next8 = AFTER, /* counter for next 8 after match found */
found = 0, /* number of tiems w found in s */
(*matrix)[AFTER] = NULL;
for (int i = 0; i < selem; i++) { /* loop over each int in s */
if (next8 < AFTER) { /* count if next8 less than AFTER */
matrix[found-1][next8++] = s[i]; /* set next8 index in matrix row */
}
else if (s[i] == w[ndx]) { /* if s[i] matches w[ndx] */
if (++ndx == welem) { /* increment ndx, compare w/welem */
/* allocate storage for next row in matrix */
if (!(matrix = realloc (matrix, (found + 1) * sizeof *matrix))) {
perror ("realloc-matrix"); /* on failure, handle error */
*n = 0;
return NULL;
}
/* (optional) set all elements in row 0 */
memset (matrix[found], 0, sizeof *matrix);
found += 1; /* increment found count */
ndx = next8 = 0; /* reset ndx, set next8 to count */
}
}
else /* otherwise, not a match and not counting */
ndx = 0; /* set match index to 0 */
}
*n = found; /* update value at n to found, so n available in main */
return matrix; /* return allocated matrix */
}
(note: the number of elements in s is provided in selem and the number of elements in w is provided by welem)
Changing your s[] in main to int s[] = {1,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0} so it is easy to verify the results, you could write you program as:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARSZ 1000 /* if you need a constant, #define one (or more) */
#define AFTER 8
/* function returning allocated pointer to array of 8 int, *n of them */
int (*sniffer (int *s, int selem, int *w, int welem, int *n))[AFTER]
{
int ndx = 0, /* match index */
next8 = AFTER, /* counter for next 8 after match found */
found = 0, /* number of tiems w found in s */
(*matrix)[AFTER] = NULL;
for (int i = 0; i < selem; i++) { /* loop over each int in s */
if (next8 < AFTER) { /* count if next8 less than AFTER */
matrix[found-1][next8++] = s[i]; /* set next8 index in matrix row */
}
else if (s[i] == w[ndx]) { /* if s[i] matches w[ndx] */
if (++ndx == welem) { /* increment ndx, compare w/welem */
/* allocate storage for next row in matrix */
if (!(matrix = realloc (matrix, (found + 1) * sizeof *matrix))) {
perror ("realloc-matrix"); /* on failure, handle error */
*n = 0;
return NULL;
}
/* (optional) set all elements in row 0 */
memset (matrix[found], 0, sizeof *matrix);
found += 1; /* increment found count */
ndx = next8 = 0; /* reset ndx, set next8 to count */
}
}
else /* otherwise, not a match and not counting */
ndx = 0; /* set match index to 0 */
}
*n = found; /* update value at n to found, so n available in main */
return matrix; /* return allocated matrix */
}
int main (void) {
int s[] = {1,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0},
w[] = {1,0,1},
n = 0,
(*result)[AFTER] = NULL;
result = sniffer (s, sizeof s/sizeof *s, w, sizeof w/sizeof *w, &n);
for (int i = 0; i < n; i++) { /* loop over result matrix */
printf ("matrix[%d] = {", i); /* output prefix */
for (int j = 0; j < AFTER; j++) /* loop over column values */
printf (j ? ",%d" : "%d", result[i][j]); /* output column value */
puts ("}"); /* output suffix and \n */
}
free (result); /* free allocated memory */
}
Example Use/Output
$ ./bin/pattern_in_s
matrix[0] = {0,0,0,0,1,1,1,1}
matrix[1] = {1,1,1,1,0,0,0,0}
If I have misunderstood your question, please let me know in a comment below and I'm happy to help further. Let me know if you have any questions.
There are several issues you must solve.
How are arrays represented?
You have arrays of integers, whose valid values can be 0 or 1. How do you datermine the length of sich an array. There are basically two possibilities:
Use a sentinel value. That's how C strings are stored: The actual string is terminated by the special value '\0', the null terminator. The memory used to store the string may be larger. In your case, you could use a value that isn't used:
enum {
END = -1
};
int a[] = {0, 1, 0, 1, END};
The disadvantage here is that you must be careful not to forget the explicit terminator. Also, if you want to find out the length of an array, you must walk it to the end. (But that's not an issue with small arrays.)
Use an explicit length that goes along with the array.
int a[] = {1, 0, 1, 0};
int alen = sizeof(a) / sizeof(*a);
The disadvantage here is that you must pass the length to any function that operates on the array. The function f(a) does not know kow long a is; the function should be something like f(a, alen). (The sizeof(a) / sizeof(*a) mechanism works only when the array a is in scope. See here for a discussion on how to find the length of an array.)
You could, of course, define a struct that combines data and length.
How do you return an array from a function?
That's your actual question. Again there are several possibilities:
Return the array. That usually means to allocate the array you want to return on the heap with malloc, which means that the caller must call free on the result at some time. The caller must know how big the returned array is. You can use sentinels as described above or you could pass in a pointer to a sive variable, which the function fills in:
int **f(..., int *length) { ... }
Call this function like this:
int length;
int **p = f(..., &length);
for (int i = 0; i < length; i++) ...
Pass in an array and hve the function fill it. That means that the function must know about the size of the array. The return value can be used to return the actual size of the array:
int f(..., int **res, int max) { ... }
Call this function like this:
int *p[20];
int length = f(..., p, 20);
for (int i = 0; i < length; i++) ...
Let's apply this to your problem.
You want to match a pattern in a string and then return a list of all 8-bit sequences after the matches. Let's represent an array as array + length. Your function might then look like this:
int sniffer(const int *s, int slen, // haystack array + length
const int *w, int wlen, // needle array + length
const int **res, int reslen) // results array
{ ... }
It passes in the arrays s and w plus their lengths. It also passes in a third array plus its length. That array hold the results. The number of valid results – the number of rows in your matrix – is the returned value.
Call this function:
int s[] = {...};
int w[] = {...};
const int *res[8];
int n = sniffer(s, sizeof(s) / sizeof(*s),
w, sizeof(w) / sizeof(*w),
res, sizeof(res) / sizeof(*res));
What happens if there are more than reslen matches? The excess matches cannot be written, of course, but do they contribute to the return value? If they do, you could pass in an array length of 0 just to see how many matches there are. (That'
s what the string function snprintf does, in a way.) If they don't you get the exact length of the result array. Both strategies are valid.
Here's an example implementation. It uses your test case #2:
#include <stdlib.h>
#include <stdio.h>
/*
* test whether the next len elements of s and w match
*/
int match(const int *s, const int *w, int len)
{
while (len-- > 0) {
if (*s++ != *w++) return 0;
}
return 1;
}
int sniffer(const int *s, int slen, // haystack array + length
const int *w, int wlen, // needle array + length
const int **res, int reslen) // results array
{
int n = 0;
for (int i = 0; i <= slen - wlen - 8; i++) {
const int *p = s + i;
if (match(p, w, wlen)) {
if (n < reslen) res[n] = p + wlen;
n++;
}
}
return n;
}
int main(void)
{
int s[] = {1, 1, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 0,
1, 0, 1, 0, 1, 0, 1, 0};
int w[] = {1, 1, 0, 0};
const int *res[8];
int reslen = sizeof(res) / sizeof(*res);
int n = sniffer(s, sizeof(s) / sizeof(*s),
w, sizeof(w) / sizeof(*w),
res, reslen);
printf("%d patterns:\n", n);
for (int i = 0; i < n && i < reslen; i++) {
printf("[%d] {", i);
for (int j = 0; j < 8; j++) {
if (j) printf(", ");
printf("%d", res[i][j]);
}
printf("}\n");
}
return 0;
}

N permutations of string (with repetitions)

I have to print first n permutations with repetitions of a string.
String is formed with characters 'a','b','c','d','e','f'.
For example, first 10 permutations would be: aaaaaa,aaaaab,aaaaac,aaaaad,aaaaae,aaaaaf,aaaaba,aaaabb,aaaabc,aaaabd.
This is my failed attempt:
int main()
{
FILE *c;
c = fopen("C:\\Users\\Korisnik\\Desktop\\tekst\\permutacija.txt", "w");
char s[6] = "abcdef";
char t[6] = "aaaaaa";
s[6] = '\0';
t[6] = '\0';
int k = strlen(t);
int m = k;
int n;
scanf("%d", &n);
int br = 0;
int i = 0;
while (br < n) {
i = 0;
while (i < 6) {
t[k-1] = s[i];
fprintf(c, "%s ", t);
fprintf(c, "\n");
i++;
br++;
if (br == n) {
exit(1);
}
}
t[k-1] = 'a';
k--;
if (k < 0) {
k = m;
}
}
return 0;
}
And my output for first 10 permutations is:
aaaaa
aaaaab
aaaaac
aaaaad
aaaaae
aaaaaf
aaaa
aaaaba
aaaaca
aaaada
Any suggestions?
(Showing a different idea)If you look carefully you will see that all the permutations are the numbers in base-7. Consider a as 0, b as 1 and so on. So for every number 1..n you will convert it into base 7 and write it (By write it I mean, in place of 0 you put a,1 - b etc). That will give you the required result. (Ofcourse in conversion you will have to append 0 to the left of the number as per number of digits you want to show). There are problems in your code:
char s[6]="abcdef";
is legal in C.
s[6]=0;
This is not as you are accessing array index out of bound which is Undefined behavior. strlen(t) is undefined behavior as t is not NUL terminated.
Also you have fprintf(c,"%s ",t); in your code - this also leads to undefined behavior, it also expects a char* which points to a nul terminated char array. This will make your realize that how irrelevant it is to have something like this
char s[6]="abcdef";
Long story short, use char s[7]="abcdef"; (same applies to t also).

Out of bounds 2D array error in C

Im stuck on this one part and I was hoping to get some help. I have a project that is basically a word search. The program reads in a file that contains the Rows and columns followed by the word search puzzle itself. You are required to create possible combinations of strings from the word search and check those combinations with a dictionary that is provided as another text document.
Here's an example of the file read in 1st is Rows and 2nd is Cols followed by the word search puzzle:
4 4
syrt
gtrp
faaq
pmrc
So I have been able to get most of the code to work except for the function that creates strings for the above file. Basically It needs to search the wordsearch and create strings, each created string gets passed on to another function to check if it's in the dictionary. However my code keeps going out of bounds when creating the strings, and it's continuing to cause Seg faults which is really frustrating.
Theses are the constants that are declared, its every possible direction to go while searching the word search puzzle for possible string combinations
const int DX_SIZE = 8;
const int DX[] = {-1,-1,-1,0,0,1,1,1};
const int DY[] = {-1,0,1,-1,1,-1,0,1};
This is the function I have to create the strings:
int strCreate(char** puzzle, char** dictionary, int n, int rows, int col){
int x, y;
int nextX, nextY, i;
char str[20] = {0};
int length = 1;
for(x = 0; x < rows; x++)
{
for(y = 0; y < col; y++)
{
//Grabs the base letter
str[0] = puzzle[x][y];
length = 1;
for(i = 0; i < DX_SIZE; i++)
{
while(length < MAX_WORD_SIZE)
{
nextX = x + DX[i]*length;
nextY = y + DY[i]*length;
// Checking bounds of next array
//This is where I'm having trouble.
if((x + nextX) < 0 || (nextX + x) > (col-1)){
printf("Out of bounds\n");
break;
}
if((y + nextY) < 0 || (nextY + y) > (rows-1)){
printf("Out of bounds\n");
break;
}
str[length] = puzzle[nextX][nextY];
//search for str in dictionary
checkStr(str, dictionary, n);
length++;
}
memset(&str[1], '\0', 19);
}
}
}
return 0;
}
I know i'm not checking the bounds properly I just can't figure out how to. When X = 1 and nextX = -1, that passes the bounds check, however say the array is at puzzle[0][0] nextX would put puzzle[-1][0] which is out of bounds causing the seg fault.
Thank you for taking the time to read, and I appreciate any help at all.
nextX and nextY are the indices used to access the array puzzle. Then the array bound check should also include the same. But the array bound check includes for example x+nextX.
// Checking bounds of next array
//This is where I'm having trouble.
if((x + nextX) < 0 || (nextX + x) > (col-1)){
printf("Out of bounds\n");
break;
}
Example:
if( nextX < 0)
printf("Out of bounds...\n");

C program displaying more characters than array size

I've written a small program to concatenate a string "20746865" upto 300 characters. The program is as follows:
#include<stdio.h>
#include<string.h>
void main()
{
char test[] = {'2','0','7','4','6','8','6','5'};
char crib[300];
int i, length = 0;
while(length <= 299)
{
for(i=0; i<8;i++)
{
crib[length] = test[i];
i=i%8;
length++;
}
}
crib[length]='\0';
printf("%s", crib);
}
The following is the output:
2074686520746865207468652074686520746865207468652074686520746865207468652074686520746865207468652074686520746865207468652074686520746865207468652074686520746865207468652074686520746865207468652074686520746865207468652074686520746865207468652074686520746865207468652074686520746865207468652074686520746865
However, when i count the number of characters in the output, it shows 304 characters. Could someone help me understand how can it print 304 characters if the array size is only 300?
The bug in your code is that the inner loop continues even when the written index is out of bounds, which causes it to continue until the next multiple of 8 generating undefined behavior.
Unlike previous replies, this version compiles and works according to your description using C99, minimizing the number of copies and iterations.
#include <stdio.h>
#include <string.h>
static const size_t OUTPUT_SIZE = 300U;
static const char INPUT[] = {'2','0','7','4','6','8','6','5'};
static const size_t INPUT_SIZE = sizeof(INPUT);
int main()
{
char output[OUTPUT_SIZE + 1];
const size_t numIter = OUTPUT_SIZE / INPUT_SIZE;
size_t idx = 0;
// copy full chunks
for (; idx < numIter; idx++)
{
memcpy(output + idx * INPUT_SIZE, INPUT, INPUT_SIZE);
}
// write the remainder
memcpy(output + numIter * INPUT_SIZE, INPUT, OUTPUT_SIZE % INPUT_SIZE);
// add null terminator
output[OUTPUT_SIZE] = '\0';
printf("result: %s\nlength: %d\n", output, strlen(output));
return 0;
}
I hope this helps.
You have undefined behavior here. You defined crib as type char[300], but you are indexing it at position 300 when you write crib[length] = '\0'. So it's not clear that your string is actually being null terminated.
You don't make any provision to see if the for loop will kick the length beyond the threshold, but instead only check in the while loop every 8 characters to see if it's already long enough/too long. After 38 complete outer loops, therefore, it hits exactly 304 characters and terminates, since 304 is not <= 299.
What you should probably do is avoid having two loops at all. Instead, keep a loop index and a calculated rolling index based on that. Untested:
#include<stdio.h>
#include<string.h>
void main() {
char test[] = {'2','0','7','4','6','8','6','5'};
char crib[301];
for (int i = 0, j = 0; i < 300; i++, j = i % 8) {
crib[i] = test[j];
}
crib[length]='\0';
printf("%s", crib);
}

In-place run length decoding?

Given a run length encoded string, say "A3B1C2D1E1", decode the string in-place.
The answer for the encoded string is "AAABCCDE". Assume that the encoded array is large enough to accommodate the decoded string, i.e. you may assume that the array size = MAX[length(encodedstirng),length(decodedstring)].
This does not seem trivial, since merely decoding A3 as 'AAA' will lead to over-writing 'B' of the original string.
Also, one cannot assume that the decoded string is always larger than the encoded string.
Eg: Encoded string - 'A1B1', Decoded string is 'AB'. Any thoughts?
And it will always be a letter-digit pair, i.e. you will not be asked to converted 0515 to 0000055555
If we don't already know, we should scan through first, adding up the digits, in order to calculate the length of the decoded string.
It will always be a letter-digit pair, hence you can delete the 1s from the string without any confusion.
A3B1C2D1E1
becomes
A3BC2DE
Here is some code, in C++, to remove the 1s from the string (O(n) complexity).
// remove 1s
int i = 0; // read from here
int j = 0; // write to here
while(i < str.length) {
assert(j <= i); // optional check
if(str[i] != '1') {
str[j] = str[i];
++ j;
}
++ i;
}
str.resize(j); // to discard the extra space now that we've got our shorter string
Now, this string is guaranteed to be shorter than, or the same length as, the final decoded string. We can't make that claim about the original string, but we can make it about this modified string.
(An optional, trivial, step now is to replace every 2 with the previous letter. A3BCCDE, but we don't need to do that).
Now we can start working from the end. We have already calculated the length of the decoded string, and hence we know exactly where the final character will be. We can simply copy the characters from the end of our short string to their final location.
During this copy process from right-to-left, if we come across a digit, we must make multiple copies of the letter that is just to the left of the digit. You might be worried that this might risk overwriting too much data. But we proved earlier that our encoded string, or any substring thereof, will never be longer than its corresponding decoded string; this means that there will always be enough space.
The following solution is O(n) and in-place. The algorithm should not access memory it shouldn't, both read and write. I did some debugging, and it appears correct to the sample tests I fed it.
High level overview:
Determine the encoded length.
Determine the decoded length by reading all the numbers and summing them up.
End of buffer is MAX(decoded length, encoded length).
Decode the string by starting from the end of the string. Write from the end of the buffer.
Since the decoded length might be greater than the encoded length, the decoded string might not start at the start of the buffer. If needed, correct for this by shifting the string over to the start.
int isDigit (char c) {
return '0' <= c && c <= '9';
}
unsigned int toDigit (char c) {
return c - '0';
}
unsigned int intLen (char * str) {
unsigned int n = 0;
while (isDigit(*str++)) {
++n;
}
return n;
}
unsigned int forwardParseInt (char ** pStr) {
unsigned int n = 0;
char * pChar = *pStr;
while (isDigit(*pChar)) {
n = 10 * n + toDigit(*pChar);
++pChar;
}
*pStr = pChar;
return n;
}
unsigned int backwardParseInt (char ** pStr, char * beginStr) {
unsigned int len, n;
char * pChar = *pStr;
while (pChar != beginStr && isDigit(*pChar)) {
--pChar;
}
++pChar;
len = intLen(pChar);
n = forwardParseInt(&pChar);
*pStr = pChar - 1 - len;
return n;
}
unsigned int encodedSize (char * encoded) {
int encodedLen = 0;
while (*encoded++ != '\0') {
++encodedLen;
}
return encodedLen;
}
unsigned int decodedSize (char * encoded) {
int decodedLen = 0;
while (*encoded++ != '\0') {
decodedLen += forwardParseInt(&encoded);
}
return decodedLen;
}
void shift (char * str, int n) {
do {
str[n] = *str;
} while (*str++ != '\0');
}
unsigned int max (unsigned int x, unsigned int y) {
return x > y ? x : y;
}
void decode (char * encodedBegin) {
int shiftAmount;
unsigned int eSize = encodedSize(encodedBegin);
unsigned int dSize = decodedSize(encodedBegin);
int writeOverflowed = 0;
char * read = encodedBegin + eSize - 1;
char * write = encodedBegin + max(eSize, dSize);
*write-- = '\0';
while (read != encodedBegin) {
unsigned int i;
unsigned int n = backwardParseInt(&read, encodedBegin);
char c = *read;
for (i = 0; i < n; ++i) {
*write = c;
if (write != encodedBegin) {
write--;
}
else {
writeOverflowed = 1;
}
}
if (read != encodedBegin) {
read--;
}
}
if (!writeOverflowed) {
write++;
}
shiftAmount = encodedBegin - write;
if (write != encodedBegin) {
shift(write, shiftAmount);
}
return;
}
int main (int argc, char ** argv) {
//char buff[256] = { "!!!A33B1C2D1E1\0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" };
char buff[256] = { "!!!A2B12C1\0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" };
//char buff[256] = { "!!!A1B1C1\0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" };
char * str = buff + 3;
//char buff[256] = { "A1B1" };
//char * str = buff;
decode(str);
return 0;
}
This is a very vague question, though it's not particularly difficult if you think about it. As you say, decoding A3 as AAA and just writing it in place will overwrite the chars B and 1, so why not just move those farther along the array first?
For instance, once you've read A3, you know that you need to make space for one extra character, if it was A4 you'd need two, and so on. To achieve this you'd find the end of the string in the array (do this upfront and store it's index).
Then loop though, moving the characters to their new slots:
To start: A|3|B|1|C|2|||||||
Have a variable called end storing the index 5, i.e. the last, non-blank, entry.
You'd read in the first pair, using a variable called cursor to store your current position - so after reading in the A and the 3 it would be set to 1 (the slot with the 3).
Pseudocode for the move:
var n = array[cursor] - 2; // n = 1, the 3 from A3, and then minus 2 to allow for the pair.
for(i = end; i > cursor; i++)
{
array[i + n] = array[i];
}
This would leave you with:
A|3|A|3|B|1|C|2|||||
Now the A is there once already, so now you want to write n + 1 A's starting at the index stored in cursor:
for(i = cursor; i < cursor + n + 1; i++)
{
array[i] = array[cursor - 1];
}
// increment the cursor afterwards!
cursor += n + 1;
Giving:
A|A|A|A|B|1|C|2|||||
Then you're pointing at the start of the next pair of values, ready to go again. I realise there are some holes in this answer, though that is intentional as it's an interview question! For instance, in the edge cases you specified A1B1, you'll need a different loop to move subsequent characters backwards rather than forwards.
Another O(n^2) solution follows.
Given that there is no limit on the complexity of the answer, this simple solution seems to work perfectly.
while ( there is an expandable element ):
expand that element
adjust (shift) all of the elements on the right side of the expanded element
Where:
Free space size is the number of empty elements left in the array.
An expandable element is an element that:
expanded size - encoded size <= free space size
The point is that in the process of reaching from the run-length code to the expanded string, at each step, there is at least
one element that can be expanded (easy to prove).

Resources