Making two arrays the same length. C(89) - c

The two arrays passed in are constants so I made two new arrays.
The first array stores a group of chars and the second array stores a second group of chars. So far I assume that the first group is bigger than the second ex. (a,b,c,d > x,y).
What the program hopes to accomplish is to make two new arrays that contain the same letters but the shorter array in this case arr2 (newarr2) has it's last char repeated until it matches the length of the first array.
examples of correct solutions.
(a,b,c,d < x,y) --> equate_arr --> (a,b,c,d = x,y,y,y)
void equate_arr(char arg2[], char arg1[]){
size_t i = 0;
size_t len1 = strlen(arg1);
size_t len2 = strlen(arg2);
char newarr2[512];
char newarr1[512];
while(i < (strlen2 - 1))
{
newarr2[i] = arg2[i];
i++;
}
i = 0;
while(i < (strlen1 - 1))
{
newarr1[i] = arg1[i];
i++;
}
i = 0;
while(strlen(newarr2) < strlen(newarr1))
{
newarr2[strlen(newarr2)] = newarr2[strlen(newarr2)-1]
}
}
Currently I have no idea what is happening because once I fiddle with this function in my code the program does not seem to run anymore. Sorry about asking about this project I'm working on so much but I really do need some assistance.
I can put the whole program in here if needed.
Revised
void tr_non_eq(char arg1[], char arg2[], int len1, int len2)
{
int i = 0;
char* arr2;
arr2 = (char*)calloc(len1+1,sizeof(char));
while(i < len2)
{
arr2[i] = arg2[i];
i++;
}
while(len2 < len1)
{
arr2[len2] = arg2[len2-1];
len2++;
}
tr_str(arg1, arr2);
}
Right now with inputs (a,b,c,d,e,f) and (x,y) and a string "cabbage" to translate the program prints out "yxyyx" and with string "abcdef" it prints out "xyy" which shows promise. I am not too sure why the arr2 array does not get filled with "y" chars as intended.

As de-duplicator says, as your code stands it effectively achieves nothing. More importantly, what it tries to do is fraught with peril.
The fact that you use strlen to determine the length of your arguments is a clear indicator that equate_arr does not expect to receive two arrays of char. Instead, it wants two NUL-terminated C-style strings. So the declaration should be more like:
void equate_arr(const char *arg2, const char *arg1)
This makes the contract a little clearer.
But note the return type: void. This says your function will not return any values to the caller. So, how did you plan to return the modified arrays?
The next big peril lies in these lines:
char newarr2[512];
char newarr1[512];
What happens if this function is called with a string which is larger than 511 characters (plus the NUL)? The phrase "buffer overrun" should be jumping out at you here.
What you need is to malloc buffers large enough to hold a duplicate of the longest string passed in. But that raises the question of how you will hand the new arrays back to the caller (remember that void return type?).
There are numerous other problems here, largely down to not having a clear definition of the contract this function is meant to meet.
One more for now while I look more closely
while(strlen(newarr2) < strlen(newarr1))
{
newarr2[strlen(newarr2)] = newarr2[strlen(newarr2)-1]
}
The very first pass through this loop overwrites the terminating NUL in newarr2, which means the next call to strlen is off into undefined behavior as it is completely at the mercy of whatever junk is sitting in your stack.
If you are unclear on C-style strings, take a look at my answer to this question which goes into great detail about them.
The following is whiteboard-code (i.e. not compiled, not tested) which would sort of do what you are wanting to achieve. It's purely for reference
// Pad a string so that it is the same length as another. Padding is done
// by replicating the final character.
//
// #param padThis: A C-style string in a non-constant buffer.
// #param bufLength: The size of the buffer containing padThis
// #param toMatchThis: A (possibly) const C-style string to act
// as a template for length
//
// Pre-conditions:
// - Both padThis and toMatchThis reference NUL-terminated sequences
// of chars
// - strlen(padThis) < bufLength. Violating this will exit the program.
// - strlen(toMatchThis) < bufLength. If not, padThis will be padded
// to bufLength characters.
//
// Post-conditons:
// - The string referenced by toMatchThis is unchanged
// - The original string at padThis has been padded if necessary to
// min(bufLength, strlen(toMatchThis))
void padString(char * padThis, size_t bufLength, const char * toMatchThis)
{
size_t targetLength = strlen(toMatchThis);
size_t originalLength = strlen(padThis);
if (originalLength >= bufLength)
{
fprintf(stderr, "padString called with an original which is longer than the buffer!\n");
exit(EXIT_FAILURE);
}
if (targetLength >= bufLength)
targetLength = bufLength -1; // Just pad until buffer full
if (targetLength <= strlen(padThis))
return; // Nothing to do
// At this point, we know that some padding needs to occur, and
// that the buffer is large enough (assuming the caller is not
// lying to us).
char padChar = padThis[originalLength-1];
size_t index = originalLength;
while (index < targetLength)
padThis[index++] = padChar;
padThis[index] = '\0';
}

Since you declared
char newarr2[512];
char newarr1[512];
as size 512 and not assigned any data, strlen will always return size of newarr1 and newarr2 as garbage since you not ended the string with a proper NULL character.
while(strlen(newarr2) < strlen(newarr1))
{
newarr2[strlen(newarr2)] = newarr2[strlen(newarr2)-1]
}
this while loop will not work properly.
for ( i = len2; i < len1; ++i )
newarr2[i] = newarr2[len2-1]
if len2 is always less than len1, you can use the above loop
if you do not know the which array will be bigger than,
size_t len1 = strlen(arg1);
size_t len2 = strlen(arg2);
char* newarr1;
char* newarr2;
int i;
if ( len1 >= len2 )
{
newarr1 = (char*)calloc(len1+1,sizeof(char));
newarr2 = (char*)calloc(len1+1,sizeof(char));
}
else
{
newarr1 = (char*)calloc(len2+1,sizeof(char));
newarr2 = (char*)calloc(len2+1,sizeof(char));
}
for ( i = 0; i < len1; ++i)
newarr1[i] = arg1[i];
for ( i = 0; i < len2; ++i)
newarr2[i] = arg2[i];
if( len1 >= len2 )
{
for ( i = len2; i < len1; ++i )
newarr2[i] = newarr2[len2-1];
}
else
{
for ( i = len1; i < len2; ++i )
newarr1[i] = newarr1[len1-1];
}
free the memory later

Related

Import a matrix of any size in C [duplicate]

How am I supposed to use dynamic memory allocations for arrays?
For example here is the following array in which i read individual words from a .txt file and save them word by word in the array:
Code:
char words[1000][15];
Here 1000 defines the number of words the array can save and each word may comprise of not more than 15 characters.
Now I want that that program should dynamically allocate the memory for the number of words it counts. For example, a .txt file may contain words greater that 1000. Now I want that the program should count the number of words and allocate the memory accordingly.
Since we cannot use a variable in place of [1000], I am completely blank at how to implement my logic. Please help me in this regard.
You use pointers.
Specifically, you use a pointer to an address, and using a standard c library function calls, you ask the operating system to expand the heap to allow you to store what you need to.
Now, it might refuse, which you will need to handle.
The next question becomes - how do you ask for a 2D array? Well, you ask for an array of pointers, and then expand each pointer.
As an example, consider this:
int i = 0;
char** words;
words = malloc((num_words)*sizeof(char*));
if ( words == NULL )
{
/* we have a problem */
printf("Error: out of memory.\n");
return;
}
for ( i=0; i<num_words; i++ )
{
words[i] = malloc((word_size+1)*sizeof(char));
if ( words[i] == NULL )
{
/* problem */
break;
}
}
if ( i != num_words )
{
/* it didn't allocate */
}
This gets you a two-dimensional array, where each element words[i] can have a different size, determinable at run time, just as the number of words is.
You will need to free() all of the resultant memory by looping over the array when you're done with it:
for ( i = 0; i < num_words; i++ )
{
free(words[i]);
}
free(words);
If you don't, you'll create a memory leak.
You could also use calloc. The difference is in calling convention and effect - calloc initialises all the memory to 0 whereas malloc does not.
If you need to resize at runtime, use realloc.
Malloc
Calloc
Realloc
Free
Also, important, watch out for the word_size+1 that I have used. Strings in C are zero-terminated and this takes an extra character which you need to account for. To ensure I remember this, I usually set the size of the variable word_size to whatever the size of the word should be (the length of the string as I expect) and explicitly leave the +1 in the malloc for the zero. Then I know that the allocated buffer can take a string of word_size characters. Not doing this is also fine - I just do it because I like to explicitly account for the zero in an obvious way.
There is also a downside to this approach - I've explicitly seen this as a shipped bug recently. Notice I wrote (word_size+1)*sizeof(type) - imagine however that I had written word_size*sizeof(type)+1. For sizeof(type)=1 these are the same thing but Windows uses wchar_t very frequently - and in this case you'll reserve one byte for your last zero rather than two - and they are zero-terminated elements of type type, not single zero bytes. This means you'll overrun on read and write.
Addendum: do it whichever way you like, just watch out for those zero terminators if you're going to pass the buffer to something that relies on them.
While Ninefingers provided an answer using an array of pointers , you can also use an array of arrays as long as the inner array's size is a constant expression. The code for this is simpler.
char (*words)[15]; // 'words' is pointer to char[15]
words = malloc (num_words * sizeof(char[15]);
// to access character i of word w
words[w][i];
free(words);
If you're working in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_LEN 15
int resizeArray(char (**wordList)[WORD_LEN], size_t *currentSize, size_t extent)
{
int result = 1;
char (*tmp)[WORD_LEN] = realloc(*wordList,
(*currentSize + extent) * sizeof **wordList);
if (tmp)
{
*currentSize += extent;
*wordList = tmp;
}
else
result = 0;
return result;
}
int main(void)
{
char *data[] = {"This", "is", "a", "test",
"of", "the", "Emergency",
"Broadcast", "System", NULL};
size_t i = 0, j;
char (*words)[WORD_LEN] = NULL;
size_t currentSize = 0;
for (i = 0; data[i] != NULL; i++)
{
if (currentSize <= i)
{
if (!resizeArray(&words, &currentSize, 5))
{
fprintf(stderr, "Could not resize words\n");
break;
}
}
strcpy(words[i], data[i]);
}
printf("current array size: %lu\n", (unsigned long) currentSize);
printf("copied %lu words\n", (unsigned long) i);
for (j = 0; j < i; j++)
{
printf("wordlist[%lu] = \"%s\"\n", (unsigned long) j, words[j]);
}
free(words);
return 0;
}
If you intend to go for C++, STL is very useful for something dynamic allocation and is very easy. You can use std::vector ..
In modern C (C99) you have an additional choice, variable length arrays, VLA, such as that:
char myWord[N];
In principle you could also do such a thing in two dimensions, but if your sizes get too big, you may risk a stack overflow. In your case the easiest thing would be to use a pointer to such an array and to use malloc / realloc to resize them:
typedef char Word[wordlen];
size_t m = 100000;
Word* words = malloc(m * sizeof(Word));
/* initialize words[0]... words[m-1] here */
for (size_t i = 0; i < m; ++i) words[i][0] = '\0';
/* array is too small? */
m *= 2;
void *p = realloc(words, m*sizeof(Word));
if (p) words = p;
else {
/* error handling */
}
.
free(words);
This code should work (modulo typos) if wordlen is a constant or a variable, as long as you keep everything inside one function. If you want to place it in a function you should declare your function something like
void myWordFunc(size_t wordlen, size_t m, char words[m][wordlen]);
that is the length parameters must come first to be known for the declaration of words.
If the 15 in your example is variable, use one of the available answers (from Ninefingers or John Boker or Muggen).
If the 1000 is variable, use realloc:
words = malloc(1000 * sizeof(char*));
// ... read 1000 words
if (++num_words > 1000)
{
char** more_words = realloc(words, 2000 * sizeof(char*));
if (more_words) {printf("Too bad");}
else {words = more_words;}
}
In my code above, the constant 2000 is a simplification; you should add another variable capacity to support more than 2000 words:
if (++num_words > capacity)
{
// ... realloc
++capacity; // will reallocate 1000+ words each time; will be very slow
// capacity += 1000; // less reallocations, some memory wasted
// capacity *= 2; // less reallocations but more memory wasted
}
Here is a little information on dynamically allocating 2d arrays:
http://www.eskimo.com/~scs/cclass/int/sx9b.html
char ** words = malloc( 1000 * sizeof(char *));
int i;
for( i = 0 ; i < 1000 ; i++)
*(words+i) = malloc(sizeof(char) * 15);
//....
for( i = 0 ; i < 1000 ; i++)
free(*(words+i));
free(words);

How to use strncpy with a for-loop in C?

I am writing a program which will take every 3 numbers in a file and convert them to their ASCII symbol. So I thought I could read the numbers into a character array, and then make every 3 elements 1 element in a second array, convert them to int and then print these as char.
I am stuck on taking every 3 elements, however. This is my code snippet for this part:
char arry[] = "073102109109112"; <--example string read from a file
char arryNew[16] = {0};
for(int i = 0; i <= sizeof(arryNew); i++){
strncpy(arryNew, arry, 3);
arryNew[i+3]='\0';
puts(arryNew);
}
What this code gives me is the first 3 numbers, fifteen times. I've tried incrementing i by 3, which gives me the first 3 numbers 5 times. How do I write a for-loop with strncpy so that after copying n chars, it moves to the next n chars?
You pass always the pointer to the beginning of the array, so you will always have the same result of course. You must include the loop counter to get at the next block:
strncpy(arryNew, &arry[i*3], 3);
Here you have a problem:
arryNew[i+3]='\0';
First of all, you don't need to set the null byte every time, because this will not change anyway. Additionally you will corrupt memory, because you use i+3 as the index so when you reach 14 and 15, it will write beyond the arrayboundary.
Your arrayNew must be longer, because your original array is 16 characters, and your target array is also. If you intend to have several 3char strings in there, then you must have 5*4 characters for your target, because each string also has the 0-byte.
And of course, you must also use the index here as well. The way it is written now, it will write beyond the array boundary, when i reaches 14 and 15.
So what you seem to want to do (not sure from your description) is:
char arry[] = "073102109109112"; <--example string read from a file
char arryNew[20] = {0};
for(int i = 0; i <= sizeof(arry); i++)
{
strncpy(&arryNew[i*4], &arry[i*3], 3);
puts(&arryNew[i*4]);
}
Or if you just want to have the individual strings printed then you can just do:
char arry[] = "073102109109112"; <--example string read from a file
char arryNew[4] = {0};
for(int i = 0; i <= sizeof(arry); i++)
{
strncpy(arryNew, &arry[i*3], 3);
puts(arryNew);
}
Making things a bit simpler: your target string doesn't change.
char arry[] = "073102109109112"; <--example string read from a file
char target[4] = {0};
for(int i = 0; i < strlen(arry) - 3; i+=3)
{
strncpy(target, arry + i, 3);
puts(target);
}
Decoding:
start at the beginning of arry
copy 3 characters to target
(note the fourth element of target is \0)
print out the contents of target
increment i by 3
repeat until you fall off the end of the string.
Some problems.
// Need to change a 3 chars, as text, into an integer.
arryNew[i] = (char) strtol(buf, &endptr, 10);
// char arryNew[16] = {0};
// Overly large.
arryNew[6]
// for(int i = 0; i <= sizeof(arryNew); i++){
// Indexing too far. Should be `i <= (sizeof(arryNew) - 2)` or ...
for (i=0; i<arryNewLen; i++) {
// strncpy(arryNew, arry, 3);
// strncpy() can be used, but we know the length of source and destination,
// simpler to use memcpy()
// strncpy(buf, a, sizeof buf - 1);
memcpy(buf, arry, N);
// arryNew[i+3]='\0';
// Toward the loop's end, code is writing outside arryNew.
// Lets append the `\0` after the for() loop.
// int i
size_t i; // Better to use size_t (or ssize_t) for array index.
Suggestion:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char Source[] = "073102109109112"; // example string read from a file
const int TIW = 3; // textual integer width
// Avoid sprinkling bare constants about code. Define in 1 place instead.
const char *arry = Source;
size_t arryLen = strlen(arry);
if (arryLen%TIW != 0) return -1; // is it a strange sized arry?
size_t arryNewLen = arryLen/TIW;
char arryNew[arryNewLen + 1];
size_t i;
for (i=0; i<arryNewLen; i++) {
char buf[TIW + 1];
// strncpy(buf, a, sizeof buf - 1);
memcpy(buf, arry, TIW);
buf[TIW] = '\0';
char *endptr; // Useful should OP want to do error checking
// TBD: test if result is 0 to 255
arryNew[i] = (char) strtol(buf, &endptr, 10);
arry += TIW;
}
arryNew[i] = '\0';
puts(arryNew); // prints Ifmmp
return 0;
}
You could use this code to complete your task i.e. to convert the given char array in form of ascii value.
char arry[] = "073102109109112";
char arryNew[16] = {0};
int i,j=0;
for(i = 0; i <= sizeof(arryNew)-2; i+=3)
{
arryNew[j]=arry[i]*100+arry[i+1]*10+arry[i+2]*1;
j++;
arryNew[j+1]='\0';
puts(arryNew);
}

Remove char from char* and return char*

I have one char array and I want to delete chars that satisfy my condition. Example I have a char array A={1,-1,0 ,1 ,-1} and I want to delete elements that equal -1. That mean output is {1,0,1}, and I want to check how many element in the array. In my example is 3. Can you help me please?
char* delete_char(char* sourceArray, char inputChar)
{
char* out=NULL;
//Need to malloc memory. But I don't know how many size will allocate because it depends on how many element that don't equal -1
return out;
}
int sizeofArray(char* sourceArray)
{
return size;
}
You have some strategies:
Calculate the exact size before allocating.
Estimate a size.
Allocate a big size memory (you probably know maximum size in worse case).
In two later cases, you can use realloc to shrink the memory. In your code, the estimated size is strlen(sourceArray)+1 if the array is a zero-terminated string, because by deleting the result is less and equal to it.
First of all, when you are using char* as an array, you also need to provide information about the length of that array (how many items it contains). Usualy this is done by a second parameter.
In your case: delete_char(char *inputArray, char inputArraySize, char inputChar).
Then you should allocate your result array to be the size of your input array (because it can contain at most as much items as the input array).
After that, you should iterate through every item in the input array and if the item fulfills your condition, add it into the result array. Of course, you have to provide also the size of the output array (for instance in an another output parameter), so you'll be able to work with it.
And lastly, when your done with working with the resulting array, don't forget do deallocate all of its memory (that means deallocate it as it was the size of the original input array, because it actially is).
You can write own function like that.
int size(char *ptr)
{
int offset = 0;
int count = 0;
while (*(ptr + offset) != '\0')
{
++count;
++offset;
}
return count;
}
Here it is:
#include <string.h>
char* delete_char(char* sourceArray, char inputChar)
{
int iNr = 0,iSize,j = 0;
iSize = strlen( sourceArray );
for( int i = 0; i < iSize; i++ )
if( sourceArray[i] == inputChar )
iNr ++;
char *newarray = new char[iNr +1];
for( int i = 0; i < iSize; i++ )
{
if( sourceArray[i] != inputChar )
newarray[j++] = sourceArray[i];
}
return newarray;
}
int sizeofArray(char* sourceArray)
{
return strlen( sourceArray );
}
PS TESTED. It works but may not be very efficient cause you check it 2 times.
You can scan the array to determine the number of elements you are removing, then allocate and appropriate memory, then copy. For example:
int sizeNeeded = 0;
for (int i = 0; i < sizeofArray(sourceArray; i++) {
if (sourceArray[I] != inputChar) sizeNeeded++;
}
char *rv = (char *) malloc(sizeNeeded * sizeOf(char));
int j = 0;
for (int i = 0; i < sizeofArray(sourceArray; i++) {
if (sourceArray[I] != inputChar) rv[j++] = sourceArray[i];
}
I did not try to compile this code but it should convey the idea

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).

Swap each even pair of characters with next pair of characters in array

I want to create an function which splits strings into two sets of characters, character by character, then merges the second set before the first, character by character. For example string "KILOS" (odd # of chars) would split into "KL" "IO" then "S" where the final output would look like "IKOLS".Meaning for every odd case, the last character from original string holds the last place in the new string. The encode function expects s2 to point to a string containing a string that is converted from s1. Any help, hint would be appreciated! Thank you.
***//I HAVE DELETED MY CODE BECAUSE I ACTUAL STUDENTS MIGHT COPY IT, AND GET CAUGHT PLAGIARISING> SORRY>***
The thing is here the code you have written is complicated and simple looping over the string can solve the problem.
void convert (char *s1, char *s2){
size_t len = strlen(s1);
for( size_t i = 0; i < len; i+=2 ){
if(i+1 < len){
s2[i+1] = s1[i];
s2[i] = s1[i+1];
}else{
s2[i] = s1[i];
}
}
s2[len]=0;
}
If you have to use the function like this:-
char s[6]="hello";
char t[6];
convert(s,t);
printf("%s\n",t);
Here ofcourse it is considered that s2 has enough memory to hold the processed string. This has literally nothing more than the copying logic. You are considering two characters each and then swapping them while copying. At last you reach a position when you are accessing an element which has no pair (odd number of elements). Then you simply copy it and move on.
In case you don't know what array subscripting means - let me tell you, s1[i] is same as *(s1+i).
Edit1
Also in your adaptation of my code in the last line you have put *s2 = 0.
It should be
*(s2+len)=0;
Another thing is in your readline code you don't need these two lines. You can do it simply like this:-
int read_line(char *str, int n)
{
int words; int store=0;
while((words=getchar())!='\n')
{
if(store<n)
{
*str++=words;
store++;
}
}
*str=0;
return store;
}
And
void encode(char *s1, char *s2)
{
int len = strlen(s1);
for( int i = 0; i < len; i+=2 ){
if(i+1 < len){
*(s2+i+1) = *(s1+i);
*(s2+i) = *(s1+i+1);
}else{
*(s2+i) = *(s1+i);
}
}
*(s2+len)='\0'; //<---- note this
}

Resources