Inserting characters in the middle of char array - c

I have a char array filled with some characters. Let's say I have "HelloWorld" in my char array. (not string. taking up index of 0 to 9)
What I'm trying to do is insert a character in the middle of the array, and push the rest to the side to make room for the new character that is being inserted.
So, I can make the char array to have "Hello.World" in it.
char ch[15]; // assume it has "HelloWorld" in it
for(int i=0; i<=strlen(ch)-1; i++) {
if(ch[i]=='o' && ch[i+1]=='W') {
for(int j=strlen(ch)-1; j>=i+2; j--) {
ch[j] = ch[j-1]; // pushing process?
}
ch[i+1] = '.';
break;
}
}
Would this work? Would there be an easier way? I might just be thinking way too complicated on this.

You need to start the inner loop from strlen(ch) + 1, not strlen(ch) - 1, because you need to move the NULL-terminator to the right one place as well. Remember that strlen returns the length of the string such that string[strlen(string)] == '\0'; you can think of strlen as a function for obtaining the index of the NULL-terminator of a C-string.

If you want to move all the characters up by one, then you could do it using memmove.
#include <string.h>
char ch[15];
int make_room_at = 5;
int room_to_make = 1;
memmove(
ch + make_room_at + room_to_make,
ch + make_room_at,
15 - (make_room_at + room_to_make)
);

Simply do:
#define SHIFT 1
char bla[32] = "HelloWorld"; // We reserve enough room for this example
char *ptr = bla + 5; // pointer to "World"
memmove(ptr + SHIFT, ptr, strlen(ptr) + 1); // +1 for the trailing null

The initial starting value for the inner loop is one short. It should be something like the following. Note too that since the characters are moved to the right, a new null terminator needs to be added:
ch[strlen(ch) + 1] = '\0';
for(j=strlen(ch); j>=i+2; j--) { // note no "-1" after the strlen
Edit As far as the "Is this a good way?" part, I think it is reasonable; it just depends on the intended purpose. A couple thoughts come to mind:
Reducing the calls to strlen might be good. It could depend on how good the optimizer is (perhaps some might be optimized out). But each call to strlen require a scan of the string looking for the null terminator. In high traffic code, that can add up. So storing the initial length in a variable and then using the variable elsewhere could help.
This type of operation has the chance for buffer overflow. Always make sure the buffer is long enough (it is in the OP).

If you're going to manipulate a char array you shouldn't make it static. By doing this:
char ch[15];
you're hardcoding the array to always have 15 characters in it. Making it a pointer would be step 1:
char* ch;
This way you can modify it as need be.

Related

CamelCase to snake_case in C without tolower

I want to write a function that converts CamelCase to snake_case without using tolower.
Example: helloWorld -> hello_world
This is what I have so far, but the output is wrong because I overwrite a character in the string here: string[i-1] = '_';.
I get hell_world. I don't know how to get it to work.
void snake_case(char *string)
{
int i = strlen(string);
while (i != 0)
{
if (string[i] >= 65 && string[i] <= 90)
{
string[i] = string[i] + 32;
string[i-1] = '_';
}
i--;
}
}
This conversion means, aside from converting a character from uppercase to lowercase, inserting a character into the string. This is one way to do it:
iterate from left to right,
if an uppercase character if found, use memmove to shift all characters from this position to the end the string one position to the right, and then assigning the current character the to-be-inserted value,
stop when the null-terminator (\0) has been reached, indicating the end of the string.
Iterating from right to left is also possible, but since the choice is arbitrary, going from left to right is more idiomatic.
A basic implementation may look like this:
#include <stdio.h>
#include <string.h>
void snake_case(char *string)
{
for ( ; *string != '\0'; ++string)
{
if (*string >= 65 && *string <= 90)
{
*string += 32;
memmove(string + 1U, string, strlen(string) + 1U);
*string = '_';
}
}
}
int main(void)
{
char string[64] = "helloWorldAbcDEFgHIj";
snake_case(string);
printf("%s\n", string);
}
Output: hello_world_abc_d_e_fg_h_ij
Note that:
The size of the string to move is the length of the string plus one, to also move the null-terminator (\0).
I am assuming the function isupper is off-limits as well.
The array needs to be large enough to hold the new string, otherwise memmove will perform invalid writes!
The latter is an issue that needs to be dealt with in a serious implementation. The general problem of "writing a result of unknown length" has several solutions. For this case, they may look like this:
First determine how long the resulting string will be, reallocating the array, and only then modifying the string. Requires two passes.
Every time an uppercase character is found, reallocate the string to its current size + 1. Requires only one pass, but frequent reallocations.
Same as 2, but whenever the array is too small, reallocate the array to twice its current size. Requires a single pass, and less frequent (but larger) reallocations. Finally reallocate the array to the length of the string it actually contains.
In this case, I consider option 1 to be the best. Doing two passes is an option if the string length is known, and the algorithm can be split into two distinct parts: find the new length, and modify the string. I can add it to the answer on request.

Iterate C char array of size 100000 takes huge time

Just try to iterate a character array of size 100000 but it takes 8-9 sec.
But for int its takes some milli second.
int i;
char str[100005];
str[0] = '\0';
for(i=1;i<10000;i++){
strcat(str, "HelloWorld");
}
for(i=1;i<strlen(str);i++){
str[i]=str[i-1];
}
Let's look at this code:
for(i = 1; i < 10000; i++){
strcat(str, "HelloWorld");
}
Think about how that call to strcat works. The strcat function works by scanning forward in the string until it finds the null terminator character, then writing the second argument there. That's pretty fast if your string is fairly short - say, it's about 10-20 characters long - but if the string you're appending onto is long (say, 10,000 characters), then strcat will spend a lot of time simply scanning to the end of the string to find the place at which to append the string. This means that each call to strcat in this function will take longer than the previous one, and eventually that last call is fairly slow.
So how can you speed this up? One option would be to store a pointer to the null terminator in the str array so that you can tell strcat where to start looking. Here's what that might look like:
size_t length = strlen("HelloWorld");
char* nextSpot = str;
for(i = 1; i < 10000; i++){
strcat(nextSpot, "HelloWorld");
nextSpot += length;
}
This means that the strcat call will always pick up right where the last one left off, speeding things up.
Hope this helps!
There are some problems with your code. The first is that you are calling strcat on a destination array that has not been initialized. You need to set str[0] = '\0'; first.
The other problems are algorithmic. To know where to insert the target string, strcat has to do strlen or equivalent every time you call it. That means that it is stepping through O(n) characters every time. That makes your algorithm ~O(n^2). Then you go and call strlen again on every single character, with the same penalty. And keep in mind that the second loop is just setting the entire array to 'H'.
If you want to copy a string 10000 times, you are better off pre-computing its length and just stepping along the buffer:
char str[100005];
const char *template = "HelloWorld";
int n = strlen(template);
char *p = str;
for(int i = 0; i < 10000; i++) {
strncpy(p, template, n);
p += n;
}
*p = '\0';
I am using strncpy here because it avoids copying the terminating '\0' of template for every copy you make.
An alternative approach would be to use modulo division (which would probably be slower) to place the characters:
char str[100005];
const char *template = "HelloWorld";
int n = strlen(template);
int end = n * 10000;
for(int i = i; i < end; i++) {
str[i] = template[i % n];
}
Both approaches take a couple of orders of magnitude less time on my machine than your original loop, because they step through the array exactly once.
The final loop copies the previous character over and over into the remainder of the buffer. Since your buffer is filled with HelloWorld, the loop copies 'H' into every location. You can use memset to do the same thing for you:
memset(str, 'H', 10000 * n);
The moral of the story is to avoid recalculating things that you can keep track of with a simple counter or pointer. If you want things to go fast, do as little work as possible.

CS50: pset2 / initials:- I've got code that works but I feel like I am taking a shortcut with setting my array size

So I am working away on the 'less comfortable' version of the initials problem in CS50, and after beginning with very verbose code I've managed to whittle it down to this:
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int c = 0;
int main(void)
{
string name = get_string();
int n = strlen(name);
char initials[10];
// first letter is always going to be the first initial
initials[0] = name[0];
// count through letters looking for spaces + add the first letter after a
// space to the initials array
for (int j = 0; j < n; j++)
{
if (name[j] == 32)
{
c += 1;
initials[c] += name[j+1];
}
}
// print out initials
for (int k = 0; k <= c; k++)
{
printf("%c", toupper(initials[k]));
}
printf("\n");
}
As it stands like that it passes, but I feel like I am copping out a little cos I just pick [10] out of the air for the initial array size which I know isn't good practice. To make it a little 'better' I've tried to run a 'for' loop to iterate through the name string and add up the number of spaces. I then want to make the array [spaces + 1] as if there are 2 spaces then there will be 3 initials. The code I am trying for that is:
string name = get_string();
int n = strlen(name);
for (int i = 0; i < n; i++)
{
if (name[i] == 32)
{
spaces +=1;
}
}
The thought is that I then make 'char initials[spaces + 1]' on the next line, but even before I can do that, compiling my code with just this 'for' loop returns a fail when I upload it for checking (although it compiles no problem). Even if I don't use any of the 'for' loops output the mere fact it is there gives me this error.
Where am I going wrong?
Any help on this would be much appreciated.
Thanks!
First of all, keep in mind that execution speed is most often more valuable than memory use. If you first go look for spaces and after that allocate memory, you have to iterate through the array twice. This is an optimization of memory use at the cost of execution speed. So it might make more sense to just allocate a "large enough" array of lets say 100 characters and keep the code that you have.
I then want to make the array [spaces + 1] as if there are 2 spaces then there will be 3 initials
Keep in mind that C strings are null terminated, so you need to allocate room for the null terminator too, spaces + 1 + 1.
compiling my code with just this 'for' loop returns a fail when I upload it for checking (although it compiles no problem). Even if I don't use any of the 'for' loops output the mere fact it is there gives me this error.
What error? Does it compile or does it not compile, your text is contradicting.
Make sure you initialize spaces to zero.
As a side note, never use "magic numbers" in C code. if (name[i] == 32), 32 is gibberish to anyone who can't cite the ASCII table by memory. In addition, it is non-portable to systems with other symbol tables that might not have the same index numbers. Instead write:
if (name[i] == ' ')
In my opinion, a good approach to cater for such situations is the one the library function snprintf uses: It requires you to pass in the string to fill and the size of that string. In ensures that the string isn't overwritten and that the string is zero-terminated.
The function returns the length of the characters written to the string if the had the string been large enough. You can now do one of two things: Guess a reasonable buffer size and accept that the string will be cut short occasionally. Or call the function with a zero length, use the return value to allocate a char buffer and then fill it with a second call.
Applying this approach to your initials problem:
int initials(char *ini, int max, const char *str)
{
int prev = ' '; // pretend there's a space before the string
int n = 0; // actual number of initials
while (*str) {
if (prev == ' ' && *str != ' ') {
if (n + 1 < max) ini[n] = *str;
n++;
}
prev = *str++;
}
if (n < max) {
ini[n] = '\0';
} else if (max > 0) {
ini[max] = '\0';
}
return n;
}
You can then either use the fixed-size bufer approach:
char *name = "Theodore Quick Brown Fox";
char ini[4];
initials(ini, sizeof(ini), name);
puts(ini); // prints "TQB", "F" is truncated
Or the two-step dynamic-size approach:
char *name = "Theodore Quick Brown Fox";
int n;
n = initials(NULL, 0, name);
char ini[n + 1];
initials(ini, sizeof(ini), name);
puts(ini); // prints "TQBF"
(Note that this implementation of initals will ignore multiple spaces and spaces at the end or at the beginning of the string. Your look-one-ahead function will insert spaces in these cases.)
You know your initials array can't be any bigger than the name itself; at most, it can't be more than half as big (every other character is a space). So use that as your size. The easiest way to do that is to use a variable-length array:
size_t n = strlen( name ); // strlen returns a size_t type, not int
char initials[n/2+1]; // n/2+1 is not a *constant expression*, so this is
// a variable-length array.
memset( initials, 0, n + 1 ); // since initials is a VLA, we can't use an initializer
// in the declaration.
The only problem is that VLA support may be iffy - VLAs were introduced in C99, but made optional in C2011.
Alternately, you can use a dynamically-allocated buffer:
#include <stdlib.h>
...
size_t n = strlen( name );
char *initials = calloc( n/2+1, sizeof *initials ); // calloc initializes memory to 0
/**
* code to find and display initials
*/
free( initials ); // release memory before you exit your program.
Although, if all you have to do is display the initials, there's really no reason to store them - just print them as you find them.
Like others have suggested, use the character constant ' ' instead of the ASCII code 32 for comparing against a space:
if ( name[j] == ' ' )
or use the isspace library function (which will return true for spaces, tabs, newlines, etc.):
#include <ctype.h>
...
if ( isspace( name[j] ) )

Concatenate char array and char

I am new to C language. I need to concatenate char array and a char. In java we can use '+' operation but in C that is not allowed. Strcat and strcpy is also not working for me. How can I achieve this? My code is as follows
void myFunc(char prefix[], struct Tree *root) {
char tempPrefix[30];
strcpy(tempPrefix, prefix);
char label = root->label;
//I want to concat tempPrefix and label
My problem differs from concatenate char array in C as it concat char array with another but mine is a char array with a char
Rather simple really. The main concern is that tempPrefix should have enough space for the prefix + original character. Since C strings must be null terminated, your function shouldn't copy more than 28 characters of the prefix. It's 30(the size of the buffer) - 1 (the root label character) -1 (the terminating null character). Fortunately the standard library has the strncpy:
size_t const buffer_size = sizeof tempPrefix; // Only because tempPrefix is declared an array of characters in scope.
strncpy(tempPrefix, prefix, buffer_size - 3);
tempPrefix[buffer_size - 2] = root->label;
tempPrefix[buffer_size - 1] = '\0';
It's also worthwhile not to hard code the buffer size in the function calls, thus allowing you to increase its size with minimum changes.
If your buffer isn't an exact fit, some more legwork is needed. The approach is pretty much the same as before, but a call to strchr is required to complete the picture.
size_t const buffer_size = sizeof tempPrefix; // Only because tempPrefix is declared an array of characters in scope.
strncpy(tempPrefix, prefix, buffer_size - 3);
tempPrefix[buffer_size - 2] = tempPrefix[buffer_size - 1] = '\0';
*strchr(tempPrefix, '\0') = root->label;
We again copy no more than 28 characters. But explicitly pad the end with NUL bytes. Now, since strncpy fills the buffer with NUL bytes up to count in case the string being copied is shorter, in effect everything after the copied prefix is now \0. This is why I deference the result of strchr right away, it is guaranteed to point at a valid character. The first free space to be exact.
strXXX() family of functions mostly operate on strings (except the searching related ones), so you will not be able to use the library functions directly.
You can find out the position of the existing null-terminator, replace that with the char value you want to concatenate and add a null-terminator after that. However, you need to make sure you have got enough room left for the source to hold the concatenated string.
Something like this (not tested)
#define SIZ 30
//function
char tempPrefix[SIZ] = {0}; //initialize
strcpy(tempPrefix, prefix); //copy the string
char label = root->label; //take the char value
if (strlen(tempPrefix) < (SIZ -1)) //Check: Do we have room left?
{
int res = strchr(tempPrefix, '\0'); // find the current null
tempPrefix[res] = label; //replace with the value
tempPrefix[res + 1] = '\0'; //add a null to next index
}

C - start traversing from the middle of a string

Just double checking because I keep mixing up C and C++ or C# but say that I have a string that I was parsing using strcspn(). It returns the length of the string up until the first delimiter it finds. Using strncpy (is that C++ only or was that available in C also?) I copy the first part of the string somewhere else and have a variable store my position. Let's say strcspn returned 10 (so the delimiter is the 10th character)
Now, my code does some other stuff and eventually I want to keep traversing the string. Do I have to copy the second half of the string and then call strncspn() from the beginning. Can I just make a pointer and point it at the 11th character of my string and pass that to strncspn() (I guess something like char* pos = str[11])? Something else simpler I'm just missing?
You can get a pointer to a location in the middle of the string and you don't need to copy the second half of the string to do it.
char * offset = str + 10;
and
char * offset = &str[10];
mean the same thing and both do what you want.
You mean str[9] for the 10th char, or str[10] for the 11th, but yes you can do that.
Just be careful that you are not accessing beyond the length of the string and beyond the size of memory allocated.
It sounds like you are performing tokenization, I would suggest that you can directly use strtok instead, it would be cleaner, and it already handles both of what you want to do (strcspn+strncpy and continue parsing after the delimiter).
you can call strcspn again with (str + 11) as first argument. But make sure that length of str is greater than 11.
n = strcspn(str, pattern);
while ((n+1) < strlen(str))
{
n2 = strcspn((str+n), pattern);
n += n2;
}
Note : using char *pos = str[11] is wrong. You should use like char *pos = str + 11;

Resources