Insert character after every 3 characters in string - c

For every three characters copied from str1 to str2, the character ch is inserted into str2.
(Input1) Enter a string: abc de
(Input2) Enter a character to be inserted: #
Output: abc# de
Code:
void insertChar(char *str1, char *str2, char ch)
{
int i, j, count = 0, flag = 0;
char *ptr1, *ptr2, *ptr3;
ptr1 = str1; //Input string
ptr3 = &str2; //char string array output
for (i = 0, j = 0;*ptr1 != '\0'; ptr1++, i++, j++, ptr3++)
{
str2[j] = str1[i];
if (*ptr1 == ' ' && flag != 1)
++count;
if (flag != 1 && count%3)
{
flag = 1;
for(ptr2 = ch;*ptr2 != '\0'; ptr2++)
{
str2[++j] = *ptr2;
ptr3++;
}
str2[++j] = ' ';
ptr3++;
}
}
str2[j] = '\0';
}
However my code is unable to run. May I know what could be the issue?

Like mentioned in the comment, there are some issues with the code.
ptr3 = &str2
In this line, you are not assigning the string to ptr3. Rather you are assigning the address of the pointer that contains the start address of the string. For example: Suppose the first character in your string is located in address location 1000. Then, str3 contains the value 1000. However, str3 itself will be located somewhere else. Let's suppose it is located at 2000. Then, ptr3 contains the value 2000 and after increment, it will point to 2001 and so on. Thus, you get wrong and dangerous values.
There is also a problem in the line for(ptr2 = ch;*ptr2 != '\0'; ptr2++). You are assigning the value of ch to ptr2. This should give you a warning. Again, the memory pointed to by ptr2 is changed. So, *ptr2 tries to dereference that memory location.
The code I would use for this:
void insertChar(char *str1, char *str2, char ch) {
int count = 0;
while (*str1) {
*str2++ = *str1++;
++count;
if (count == 3) {
*str2++ = ch;
count = 0;
}
}
*str2 = '\0';
}
Some recommendations:
Try to declare the variables as close to their usage as possible.
Use -Wall option when compiling your programs

Related

strcat adds junk to the string

I'm trying to reverse a sentence, without changing the order of words,
For example: "Hello World" => "olleH dlroW"
Here is my code:
#include <stdio.h>
#include <string.h>
char * reverseWords(const char *text);
char * reverseWord(char *word);
int main () {
char *text = "Hello World";
char *result = reverseWords(text);
char *expected_result = "olleH dlroW";
printf("%s == %s\n", result, expected_result);
printf("%d\n", strcmp(result, expected_result));
return 0;
}
char *
reverseWords (const char *text) {
// This function takes a string and reverses it words.
int i, j;
size_t len = strlen(text);
size_t text_size = len * sizeof(char);
// output containst the output or the result
char *output;
// temp_word is a temporary variable,
// it contains each word and it will be
// empty after each space.
char *temp_word;
// temp_char is a temporary variable,
// it contains the current character
// within the for loop below.
char temp_char;
// allocating memory for output.
output = (char *) malloc (text_size + 1);
for(i = 0; i < len; i++) {
// if the text[i] is space, just append it
if (text[i] == ' ') {
output[i] = ' ';
}
// if the text[i] is NULL, just get out of the loop
if (text[i] == '\0') {
break;
}
// allocate memory for the temp_word
temp_word = (char *) malloc (text_size + 1);
// set j to 0, so we can iterate only on the word
j = 0;
// while text[i + j] is not space or NULL, continue the loop
while((text[i + j] != ' ') && (text[i + j] != '\0')) {
// assign and cast test[i+j] to temp_char as a character,
// (it reads it as string by default)
temp_char = (char) text[i+j];
// concat temp_char to the temp_word
strcat(temp_word, &temp_char); // <= PROBLEM
// add one to j
j++;
}
// after the loop, concat the reversed version
// of the word to the output
strcat(output, reverseWord(temp_word));
// if text[i+j] is space, concat space to the output
if (text[i+j] == ' ')
strcat(output, " ");
// free the memory allocated for the temp_word
free(temp_word);
// add j to i, so u can skip
// the character that already read.
i += j;
}
return output;
}
char *
reverseWord (char *word) {
int i, j;
size_t len = strlen(word);
char *output;
output = (char *) malloc (len + 1);
j = 0;
for(i = (len - 1); i >= 0; i--) {
output[j++] = word[i];
}
return output;
}
The problem is the line I marked with <= PROBLEM, On the first word which in this case is "Hello", it does everything just fine.
On the second word which in this case is "World", It adds junky characters to the temp_word,
I checked it with gdb, temp_char doesn't contain the junk, but when strcat runs, the latest character appended to the temp_word would be something like W\006,
It appends \006 to all of the characters within the second word,
The output that I see on the terminal is fine, but printing out strcmp and comparting the result with expected_result returns -94.
What can be the problem?
What's the \006 character?
Why strcat adds it?
How can I prevent this behavior?
strcat() expects addresses of the 1st character of "C"-strings, which in fact are char-arrays with at least one element being equal to '\0'.
Neither the memory temp_word points to nor the memory &temp_char points to meet such requirements.
Due to this the infamous undefined behaviour is invoked, anything can happen from then on.
A possible fix would be to change
temp_word = (char *) malloc (text_size + 1);
to become
temp_word = malloc (text_size + 1); /* Not the issue but the cast is
just useless in C. */
temp_word[0] = '\0';
and this
strcat(temp_word, &temp_char);
to become
strcat(temp_word, (char[2]){temp_char});
There might be other issues with the rest of the code.
The root cause of junk characters is you use wrong input for the 2nd argument of strcat function. see explain below:
At the beginning of your function you declare:
int i, j;
size_t len = strlen(text);
size_t text_size = len * sizeof(char);
// output containst the output or the result
char *output;
// temp_word is a temporary variable,
// it contains each word and it will be
// empty after each space.
char *temp_word;
// temp_char is a temporary variable,
// it contains the current character
// within the for loop below.
char temp_char;
you can print variable's addresses in stack, they will be something like this:
printf("&temp_char=%p,&temp_word=%p,&output=%p,&text_size=%p\n", &temp_char, &temp_word,&output,&text_size);
result:
&temp_char=0x7ffeea172a9f,&temp_word=0x7ffeea172aa0,&output=0x7ffeea172aa8,&text_size=0x7ffeea172ab0
As you can see, &temp_char(0x7ffeea172a9f) is at the bottom of the stack, next 1 byte is &temp_word(0x7ffeea172aa0), next 8 bytes is &output(0x7ffeea172aa8), and so on(I used 64bit OS, so it takes 8 bytes for a pointer)
// concat temp_char to the temp_word
strcat(temp_word, &temp_char); // <= PROBLEM
refer strcat description here: http://www.cplusplus.com/reference/cstring/strcat/
the strcat second argument = &temp_char = 0x7ffeea172a9f. strcat considers that &temp_char(0x7ffeea172a9f) is the starting point of the source string, instead of adding only one char as you expect it will append to temp_word all characters starting from &temp_char(0x7ffeea172a9f) , until it meets terminating null character
The function strcat deals with strings.
In this code snippet
// assign and cast test[i+j] to temp_char as a character,
// (it reads it as string by default)
temp_char = (char) text[i+j];
// concat temp_char to the temp_word
strcat(temp_word, &temp_char); // <= PROBLEM
neither the pointer temp_word nor the pointer &temp_char points to a string.
Moreover array output is not appended with the terminating-zero character for example when the source string consists from blanks.
In any case your approach is too complicated and has many redundant code as for example the condition in the for loop and the condition in the if statement that duplicate each other.
for(i = 0; i < len; i++) {
//…
// if the text[i] is NULL, just get out of the loop
if (text[i] == '\0') {
break;
}
The function can be written simpler as it is shown in the demonstrative program below.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
char * reverse_words( const char *s )
{
char *result = malloc( strlen( s ) + 1 );
if ( result != NULL )
{
char *p = result;
while ( *s != '\0' )
{
while ( isblank( ( unsigned char )*s ) )
{
*p++ = *s++;
}
const char *q = s;
while ( !isblank( ( unsigned char )*q ) && *q != '\0' ) ++q;
for ( const char *tmp = q; tmp != s; )
{
*p++ = *--tmp;
}
s = q;
}
*p = '\0';
}
return result;
}
int main(void)
{
const char *s = "Hello World";
char *result = reverse_words( s );
puts( s );
puts( result );
free( result );
return 0;
}
The program output is
Hello World
olleH dlroW

My program which creates a abbreviation of an char array, does not print anything. Where is my mistake?

I am supposed to create a program, which creates an array with the abbreviation of an constant char Array. While my program does not return any errors, it also does not print any characters at my certain printf spots. Because of that I assume that my program does not work properly, and it isn't filling my array with any characters.
void abbrev(const char s[], char a[], size_t size) {
int i = 0;
while (*s != '\0') {
printf('%c', *s);
if (*s != ' ' && *s - 1 == ' ') {
a[i] = *s;
i++;
printf('%c', a[i]);
}
s++;
}
}
void main() {
char jordan1[60] = " Electronic Frontier Foundation ";
char a[5];
size_t size = 5;
abbrev(jordan1, a, size);
system("PAUSE");
}
The actual result is nothing. At least I assume so, since my console isn't showing anything. The result should be "EFF" and the size_t size is supposed to limit my char array a, in case the abbreviation is too long. So it should only implement the letters until my array is full and then the '\0', but I did not implement it yet, since my program is apparantly not filling the array at all.
#include <stdio.h>
#include <ctype.h>
/* in: the string to abbreviate
out: output abbreviation. Function assumes there's enough room */
void abbrev(const char in[], char out[])
{
const char *p;
int zbPosOut = 0; /* current zero-based position within the `out` array */
for (p = in; *p; ++p) { /* iterate through `in` until we see a zero terminator */
/* if the letter is uppercase
OR if (the letter is alphabetic AND we are not at the zero
position AND the previous char. is a space character) OR if the
letter is lowercase and it is the first char. of the array... */
if (isupper(*p) || (isalpha(*p) && (p - in) > 0 && isspace(p[-1]))
|| (islower(*p) && p == in)) {
out[zbPosOut++] = *p; /* ... then the letter is the start letter
of a word, so add it to our `out` array, and
increment the current `zbPosOut` */
}
}
out[zbPosOut] = 0; /* null-terminate the out array */
}
This code says a lot in few lines. Let's take a look:
isupper(*p) || (isalpha(*p) && (p - in) > 0 && isspace(p[-1]))
|| (islower(*p) && p == in)
If the current character (*p) is an uppercase character OR if it is alphabetc (isalpha(*p) and the previous character p[-1] is a space, then we may consider *p to be the first character of a word, and it should be added to our out array. We include the test (p - in) > 0 because if p == in, then we are at the zero position of the array and therefore p[-1] is undefined.
The order in this expression matters a lot. If we were to put (p - in) > 0 after the isspace(p[-1]) test, then we would not be taking advantage of the laziness of the && operator: as soon as it encounters a false operand, the following operand is not evaluated. This is important because if p - in == 0, then we do not want to evaluate the isspace(p[-1]) expression. The order in which we have written the tests makes sure that isspace(p[-1]) is evaluated after making sure we are not at the zero position.
The final expression (islower(*p) && p == in) handles the case where the first letter is lowercase.
out[zbPosOut++] = *p;
We append the character *p to the out array. The current position of out is kept track of by the zbPosOut variable, which is incremented afterwards (which is why we use postscript ++ rather than prefix).
Code to test the operation of abbrev:
int main()
{
char jordan1[] = " electronic frontier foundation ";
char out[16];
abbrev(jordan1, out);
puts(out);
return 0;
}
It gives eff as the output. For it to look like an acronym, we can change the code to append the letter *p to out to:
out[zbPosOut++] = toupper(*p);
which capitalizes each letter added to the out array (if *p is already uppercase, toupper just returns *p).
void print_without_duplicate_leading_trailing_spaces(const char *str)
{
while(*str == ' ' && *str) str++;
while(*str)
{
if(*str != ' ' || (*str == ' ' && *(str + 1) != ' ' && *str))
{
putchar(*str);
}
str++;
}
}
What you want to do could be simplified with a for() loop.
#include <stdio.h>
#include <string.h>
void abbrev(const char s[], char a[], size_t size) {
int pos = 0;
// Loop for every character in 's'.
for (int i = 0; i < strlen(s); i++)
// If the character just before was a space, and this character is not a
// space, and we are still in the size bounds (we subtract 1 for the
// terminator), then copy and append.
if (s[i] != ' ' && s[i - 1] == ' ' && pos < size - 1)
a[pos++] = s[i];
printf("%s\n", a); // Print.
}
void main() {
char jordan1[] = " Electronic Frontier Foundation ";
char a[5];
size_t size = 5;
abbrev(jordan1, a, size);
}
However, I don't think this is the best way to achieve what you are trying to do. Firstly, char s[0] cannot be gotten due to the check on the previous character. Which brings me to the second reason: On the first index you will be checking s[-1] which probably isn't a good idea. If I were implementing this function I would do this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void abbrev(const char s[], char a[], size_t size) {
char *str = strdup(s); // Make local copy.
size_t i = 0;
// Break it up into words, then grab the first character of each word.
for (char *w = strdup(strtok(str, " ")); w != NULL; w = strtok(NULL, " "))
if (i < size - 1)
a[i++] = w[0];
free(str); // Release our local copy.
printf("%s\n", a);
}
int main() {
char jordan1[] = "Electronic Frontier Foundation ";
char a[5];
size_t size = 5;
abbrev(jordan1, a, size);
return 0;
}

Unexpected segmentation fault when trying to mix some string

I need to manipulate an string in this way:
If the character is '+' or '-' or '/' or '*', move them to the end of buffer, if not, move to the beginning of the buffer.
My solution is quite simple:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void mix_the_string(char ** buff, char ** string)
{
printf("The string which will be printed is : %s\n",*string);
int i = 0;
int j = strlen(*string) - 1;
while(i< strlen(*string))
{
if(*string[i] != '+' || *string[i] != '-' || *string[i] != '*' || *string[i] != '/')
{
printf("in the first if, i = %d, *string[i] = '%d'\n",i,(int)*string[i]);
*buff[i] = *string[i];
}
else
{
printf("in the second if, i = %d, *string[i] = '%d'\n",i,(int)*string[i]);
*buff[j] = *string[i];
}
i++;
j--;
}
}
int main()
{
char * buff = (char *) malloc(50);
char * string = (char *) malloc(50);
string = "1+2+3";
mix_the_string(&buff,&string);
puts(buff);
free(buff);
free(string);
return 0;
}
The output of this code is:
The string which will be printed is : 1+2+3
in the first if, i = 0, *string[i] = '49'
in the first if, i = 1, *string[i] = '49'
Segmentation fault
I expected with this example that output would be like:
The string which will be printed is : 1+2+3
in the first if, i = 0, *string[i] = '49'
in the second if, i = 1, *string[i] = '43'
in the first if, i = 2, *string[i] = '50'
in the second if, i = 3, *string[i] = '43'
in the first if, i = 4, *string[i] = '51'
123++
Where am I going wrong?
There is difference between *string[i] and (*string)[i] notation. [] has higher precedence than * operator. You pass string by pointer to pointer, so you should call (*string)[i] in every line of your code.
(*string)[i] means - dereference pointer to array and get i-th element of string array
now you are doing
*string[i] - get i-th element of string array (!! but this is not array, this is only one element) and dereference first element
Do the same with buff.
And in main function you should copy 1+2+3 string literal into string buffer for example by strcpy function.
There are lot of bugs in your code.
first string = "1+2+3"; and then doing free(string) is not correct.
First copy it using strcpy(string,"1+2+3"); and then
free(string)
string is double pointer in mix_the_string(). Accessing like *string[i] is not correct because string is not array of pointer. instead of this use *(*string+i). Same applicable for buf also.
finally casting of malloc is not required. just char * buff = malloc(50); is fine.
And moreover you don't need to pass &string to mix_the_string(). just pass string thats enough.
Here is the expected code which you want
void mix_the_string(char ** buff, char ** string)
{
printf("The string which will be printed is : %s\n", *string);
int i = 0;
int j = strlen(string[0]) - 1;
while (i < strlen(string[0]))
{
if (*(*string + i) != '+' || *(*string + i) != '-' || *(*string + i) != '*' || *(*string + i) != '/')
{
printf("in the first if, i = %d, *string[i] = '%d'\n", i, *(*string + i));
*(*buff + i) = *(*string + i);
}
else
{
printf("in the second if, i = %d, *string[i] = '%d'\n", i, *(*string + i));
*(*buff + j) = *(*string + i);
}
i++;
j--;
}
}
int main()
{
char * buff = (char *)malloc(50);
char * string = (char *)malloc(50);
strcpy(string, "1+2+3");
mix_the_string(&buff, &string);
puts(buff);
free(buff);
free(string);
return 0;
}

Function to reverse a two-dimensional set of strings in C isn't reversing more than the first and last characters

this is my first post in Stack Overflow. If I am missing anything, please let me know and I will try to add more information.
The function below is only supposed to use pointer operations and not array operations, as part of an assignment.
I have this function in C that is part of a larger program:
void reverseString(char strings[NUM_STRINGS][STRING_LENGTH])
{
int i, j;
char *ptr; //Declare pointer variable.
for (i = 0; i < NUM_STRINGS; i++)
{
ptr = strings[i];
do { //Here, we ignore the null terminators in the char array.
ptr++;
} while (*ptr != '\0');
ptr--; //Iterate the pointer variable once downward.
j = i;
while (strings[j] < ptr) //While loop for reversing the string
{
//printf("ptr: %d\n", ptr);
//printf("strings[j]: %d\n", strings[j]);
char temp = *strings[j];
*strings[j++] = *ptr;
*ptr-- = temp;
}
}
}
What it is supposed to do is accept a 2D char array with 4 strings and with each string holding up to 32 bytes of text. Then, it reverses each string in-place in the array. For example, if I input the four strings:
Hello
World
Good
morning
It is supposed to then return:
olleH
dlroW
dooG
gninrom
However, what ends up happening is that only the first and last characters of each string are reversed. For example:
oellH
dorlW
dooG
gorninm
I have tried different solutions such as using i instead of j in the while loop or using prefix ++ instead of suffix, but nothing has worked yet. Any pointers as to what I should be looking for?
Thank you.
The solution is below. As described in my comment below, I added a secondary pointer instead of using strings[j] in the loop. The pointer now references to the beginning of the string instead of the entire array of strings.
void reverseString(char strings[NUM_STRINGS][STRING_LENGTH])
{
int i, j;
char *ptr; //Declare pointer variable.
char *ptr2;
for (i = 0; i < NUM_STRINGS; i++)
{
ptr = strings[i];
ptr2 = strings[i];
do { //Here, we ignore the null terminators in the char array.
ptr++;
} while (*ptr != '\0');
ptr--; //Iterate the pointer variable once downward.
j = i;
while (ptr2 < ptr) //While loop for reversing the string
{
char temp = *ptr2;
*ptr2++ = *ptr;
*ptr-- = temp;
}
}
}

Why is my pointer disappearing?

I have a class that is meant to return a char** by splitting one char* into sentences. I can allocate the memory and give it values at a certain point, but by the time I try to return it, it's completely missing.
char **makeSentences(char *chapter, int *nSentences){
int num = *nSentences;
char* chap = chapter;
char **sentences;
sentences = (char**) malloc(sizeof(char*) * num);
int stops[num + 1];
stops[0] = 0;
int counter = 0;
int stop = 1;
while (chap[counter] != '\0'){
if (chap[counter] == '.'){
stops[stop] = counter + 1;
printf("Place: %d\nStop Number: %d\n\n", counter, stop);
stop++;
}
counter++;
}
for (int i = 0; i < num; i++){
int length = stops[i+1] - stops[i];
char characters[length+1];
memcpy(characters, &chap[stops[i]], length);
characters[length] = '\0';
char *sentence = characters;
sentences[i] = sentence;
printf("%s\n",sentence);
printf("%s\n", sentences[i]);
}
char* testChar = sentences[0];
printf("%s\n", sentences[0]);
printf("%s]n", testChar);
return sentences;
}
The last two printing lines don't print anything but a newline, while the exact same lines (in the for loop) print as expected. What is going on here?
The problem is these three lines:
char characters[length+1];
char *sentence = characters;
sentences[i] = sentence;
Here you save a pointer to a local variable. That variable characters will go out of scope every iteration of the loop, leaving you with an "array" of stray pointers.
While not standard in C, almost all systems have a strdup function whichg duplicates a string by calling malloc and strcpy. I suggest you use it (or implement your own).

Resources