Replace a subarray with a character in C - c

I have an array and I need to replace a subarray from this array with a character.
unsigned char * data = {'a','b','c','d','e'};
I need to delete 'a','b''c' and insert 'R'
The final array will be: unsigned char * data = {'R','d','e'};
With only 3 elements.
How can I do that in C?

You say you think of data as an array, therefore it is better that you declare data as an array instead of a pointer. (The way your code is now you have a pointer that is initialized incorrectly by casting the character 'a' to a char * pointer. That way it will not be pointing anywhere.)
You can replace characters by assigning to elements of the array, and you can shift parts of the data in the array using memmove.
Which means that maybe you want something like this:
unsigned char data[] = {'a','b','c','d','e'};
data[0] = 'R';
memmove(data + 1, data + 3, sizeof(data) - 3);
The memmove call moves sizeof(data) - 3 bytes of data from address data + 3 to address data + 1. The function memmove even works when the regions of memory between which you are moving bytes of data overlap.
If you then print the relevant part of your data:
fwrite(data, 1, sizeof(data) - 2, stdout);
putchar('\n');
This will get you the output:
Rde
However, notice that the size of the array will not have changed. It still will be five characters long. So replacing abc by something longer than three characters will not work like this. Also, this array is not a null-terminated string, which is the more usual way to have sequences of characters in C.
If you prefer to use a string "abcde" instead of what you are doing now (but then why call it "data"?), add a comment below this answer, and I'll extend it.

for(int i = 0; i < 5; i++){
if (data[i] > 96 && data[i] < 100) data[i] = 'R';
}

How about the following way?
unsigned char * data = {'a','b','c','d','e'};
int length = strlen(data);
unsigned char * output = (unsigned char *)malloc(sizeof(unsigned char)*length);
for(int i = 0, j =0; i < length; i++, j++){
if (i+2 < length && data[i] == 'a' && data[i+1] == 'b && data[i+2] == 'c') {
output[j]='R';
i++;
i++;
}
else
output[j]=data[i];
}

Related

copy two arrays of int to one char* in C

I have to arrays of int for example arr1={0,1,1,0,0}, arr2={1,0,1,1,1} and I need to return 1 char* created by malloc that will be shown like this : "01100,10111".
when I do for loop it doesn't work, how can I do it ?
char* ans = (char*)malloc((size * 2+1) * sizeof(int));
for (int i = 0; i < size; i++)
ans[i] = first[i];
ans[size] = ",";
for (int i = size+1; i < 2*size+1; i++)
ans[i] = second[i];
Among the multitude of problems:
Your allocation size is wrong. It should include space for the separating comma and the terminating nullchar. sizeof(int) is wrong regardless, it should be sizeof(char) and as-such can be omitted (sizeof(char) is always 1).
Your storage is wrong. You want to store characters, and your values should be adjusted relative to '0'.
Your indexing of the second loop is wrong.
In reality, you don't need the second loop in the first place:
char* ans = malloc(size * 2 + 2);
for (int i = 0; i < size; i++)
{
ans[i] = '0' + first[i];
ans[size+1+i] = '0' + second[i];
}
ans[size] = ',';
ans[2*size+1] = 0;
That's it.
1.
char* ans = (char*)malloc((size * 2+1) * sizeof(int));
What is size here? It is not defined and declared in the provided code.
You do not need to cast the return value of malloc() to char. In fact, you do not need to cast the return value of malloc() anymore. It is a habit from the early C days.
Why do you need a char pointer here at all exactly? If you want to print 01100,10111 there is no need to use a char pointer for the output of the integer values.
2.
for (int i = 0; i < size; i++)
ans[i] = first[i];
Again what is size here?
What is first here? If it isn´t a pointer this statement is invalid.
3.
ans[size] = ",";
This operation is invalid. You are trying to assign a string to a pointer.
By the way, I don´t know what you trying to do with this statement. You can incorporate the comma separate in the output of 01100,10111, without your intend to include it int the memory of the int arrays itself.
4.
for (int i = size+1; i < 2*size+1; i++)
ans[i] = second[i];
Same as above: What is value and the type of size?
What is second? If it isn´t it a pointer this statement is invalid.
5.
To answer to the question title:
(How to) Copy two arrays of int to one char* in C
This isn´t possible. You can´t copy two arrays with its data to a pointer to char.
There are at least four issues with your code.
You malloc the wrong size, you want to use sizeof(char).
You need to zero terminate it, so you need to add extra room for the terminating zero
char* ans = (char*)malloc((size * 2+2) * sizeof(char));
second[size * 2+1] = 0;
Also the indexing of the second loop is wrong. You are accessing second array out of bounds. Make the loop more like the first.
We also need to convert the integer value to a char in the loops.
for (int i = 0; i < size; i++)
ans[size+i+1] = second[i] + '0';

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);
}

Convert char in char array to its own char array in ANSI C

I have a char array representing a double precision floating point number in hex form.
char *hex = ""402499999999999A"
I want to extract each char in hex as its own char array and read it into an unsigned int num. For example, I tried
sscanf((char *)&hex[3], "%X", &num);
But this doesn't give me the 4th char as an individual char array, it gives me the sub char array from the 4th position on, which I suppose is because arrays are given by the pointer of their first element.
Is there a better way to do this? I looked at strcpy and it seems that I can only copy the first n chars, so that's no good.
You can do this in many ways. One way is as follows (which is the correct way of how you were doing it):
char only_1_char[2] = {'\0', '\0'};
only_1_char[0] = hex[3];
sscanf(only_1_char, "%X", &num);
and a more efficient solution:
if (hex[3] <= '9')
num = hex[3] - '0';
else
num = hex[3] - 'A' + 10;
This is just a sample, though. In truth you need to take care of invalid input and lower cases if that is a possibility.
Try something like this:
for(i = 0; src[i] != 0; i++) {
if(src[i]) <= '9') {
dest[i] = src[i] - '0';
} else {
dest[i] = toupper(src[i]) - 'A' + 10;
}
}
It can be improved with error handling (e.g. detect if "src[i]" contains a valid/sane character).

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

How to copy integer array contents to a character pointer?

I have a character pointer , char *buf;
I have a array of integers , int console_buffer[256];
I need to copy the console_buffer contents to character buf.
How do I do this? The buf and console_buffer are part of different structures.
Going by your comment,
buf = malloc(256); // 257 if console_buffer may be full without EOF
/* if you want to allocate just as much space as needed, locate the EOF in console_buffer first */
for(int i = 0; i < 256 && console_buffer[i] != -1; ++i){
buf[i] = (char)console_buffer[i];
}
If you already allocated the memory for buf, and if each integer is between 0 and 9, you can do:
for(int i = 0; i < 256; i++)
{
buf[i] = '0' + console_buffer[i]; /* convert 1 to '1', etc. */
}
If the integers are larger than 9, you can use the sprintf function.
Reading your new comment, perhaps you can also achieve your goal by reading from console buffer directly to an array of chars until you have -1 (check by integers comparison, or by strcmp, or by comparing the 2 last characters to 0 and to 1).
I think this is a better way to convert values to chars
int i = 0;
while (i <= 256) {
buf[i] = (char) console_buffer[i];
i++;
}

Resources