Running into an issue with setting character at a specific position using pointers in C.
The code is accurately placing the character in the correct position, but the current character in that position is not being moved over.
The issue is that the current letter is being skipped over when position is found, but adding *dest++ = *string within the IF block when position is found causes the program to halt.
Example:
the string is "bigmoney". Letter to add is 'X'. The position is 3.
Output should be "bigXmoney"
Current output is "bigXoney" using the code below.
Any suggestions would be appreciated. Thanks!
Updated code:
void addLetter(char string[STRING_LENGTH], char letterToAdd, int pos)
{
// store array in pointer
char *stringHolder = string;
char *dest = string;
int posCounter = 0;
// loop through string while not null
while (*stringHolder) {
// position found, add the character
if (posCounter == pos) {
*dest++ = letterToAdd;
} else {
*dest++ = *stringHolder;
}
// increment position counter
posCounter++;
// move the pointer position
stringHolder++;
}
//reset stringholder pointer;
*dest = '\0';
}
If you don't want to use standard C string functions then the function can look the following way
char * addLetter( char s[], char c, size_t pos )
{
size_t i = 0;
while ( i < pos && s[i] ) ++i;
if ( i == pos )
{
do
{
char tmp = s[i];
s[i++] = c;
c = tmp;
} while ( c );
s[i] = c;
}
return s;
}
If you need to use only pointers inside the function then it can look like
char * addLetter( char s[], char c, size_t pos )
{
char *p = s;
while ( *p && p != s + pos ) ++p;
if ( p == s + pos )
{
do
{
char tmp = *p;
*p++ = c;
c = tmp;
} while ( c );
*p = c;
}
return s;
}
Here is a demonstrative program
#include <iostream>
char * addLetter( char s[], char c, size_t pos )
{
char *p = s;
while ( *p && p != s + pos ) ++p;
if ( p == s + pos )
{
do
{
char tmp = *p;
*p++ = c;
c = tmp;
} while ( c );
*p = c;
}
return s;
}
int main()
{
const size_t STRING_LENGTH = 10;
char s[STRING_LENGTH] = "bigmoney";
std::cout << s << std::endl;
std::cout << addLetter( s, 'X', 3 ) << std::endl;
return 0;
}
Its output is
bigmoney
bigXmoney
The easy way: Use std::string::insert.
Assuming std::string is forbidden in this assignment, start at the end of the string and work backward until you pass pos moving each character (including the null terminator) up one slot. Now you have an empty spot at pos and can safely write in the new value.
shorter if memcpy is allowed.
char * addLetter(char s[], char c, size_t pos)
{
int len = strlen(s);
if (pos > len || len + 1 >= STRING_LENGTH)
return NULL;
else
{
**memcpy(s + pos + 1, s + pos, len - pos);
s[pos] = c;**
return s;
}
}
Related
I am trying to write a function that takes in variables cipher, userinput, alphabet and outputs the replace letters. for example at execution it takes in an argument argv ZYXWVUTSRQPONMLKJIHGFEDCBA. requests a user to input anything then switches only the letters for example input aBc should output zYx
// function that takes in cipher(c), userinput(u) and alphabet(a) and outputs cipher text
void cipher_text(string c, string u, string a)
{
string result = u;
for (int i = 0; i < strlen(u); i++)
{
for (int k = 0; k < strlen(a); k++)
{
if (tolower(u[i]) == a[k])
{
if(islower(u[i]))
{
result[i] = tolower(c[k]);
printf("%s %s\n",result,c);
}
else
{
result[i] = toupper(c[k]);
}
}
}
}
// printf("ciphertext: %s\n", result);
}
with cipher as YUKFRNLBAVMWZTEOGXHCIPJSQD
and userinput as abcd
I was expecting yukf but got qidc
The problem of the function is this inner for loop
for (int k = 0; k < strlen(a); k++)
{
if (tolower(u[i]) == a[k])
{
if(islower(u[i]))
{
result[i] = tolower(c[k]);
printf("%s %s\n",result,c);
}
else
{
result[i] = toupper(c[k]);
}
}
}
You need to break it as soon as a letter is found in the string pointed to by the pointer a. Otherwise there can be a chain of changes.
Also using the function strlen is inefficient and redundant.
Instead of the for loop you could use standard function strchr.
The function can be declared and defined the following way
string cipher_text( string c, string u, string a )
{
for ( string p = u; *p != '\0'; p++ )
{
string pos = strchr( a, tolower( ( unsigned char )*p ) );
if ( pos != NULL )
{
size_t i = pos - a;
*p = islower( ( unsigned char )*p )
? tolower( c[i] )
: c[i];
}
}
return u;
}
Pay attention to that instead of the typedef name string it is better to use its underlaying type char *.
In this case the function can look the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char * cipher_text( const char *c, char *u, const char *a )
{
for (char *p = u; *p != '\0'; p++)
{
const char *pos = strchr( a, tolower( ( unsigned char )*p ) );
if (pos != NULL)
{
size_t i = pos - a;
*p = islower( ( unsigned char )*p )
? tolower( c[i] )
: c[i];
}
}
return u;
}
int main( void )
{
const char *c = "XYZ";
const char *a = "abc";
char u[] = "c_B_a";
puts( cipher_text( c, u, a ) );
}
The program output is
z_Y_x
I want to write a C program, that returns a new string allocated on the heap. This string is obtained by doubling all occurrences of “c” in a string (“abcdc” becomes “abccdcc” after doubling “c”).
This is my code and I don't really see where the problem is to fix it!
size_t taille = stringLength(str);
size_t k=0;
size_t q=0;
while (*str!='\0')
{
if (*str == c)
{
k=k+1;
}
++str;
}
char *nouvelle=malloc(taille+1+k);
int i,j= 0;
while(*str !='\0')
{
if (str[i] != c)
{
j=i;
nouvelle[j]=str[i];
}
else
{
j=i;
++q;
nouvelle[j]=str[i];
j=i+q;
nouvelle[j++]=str[i];
}
++i;
}
nouvelle[taille+1+k]='\0';
return nouvelle;
}
There are two problems with your code.
The first one is that after this while loop
while (*str!='\0')
{
if (*str == c)
{
k=k+1;
}
++str;
}
the pointer str points to the end of the string that is to the terminating zero character '\0'.
The second one is that you are using the uninitialized variable i
int i,j= 0;
while(*str !='\0')
{
if (str[i] != c)
{
j=i;
//..
This declaration
int i,j= 0;
is not the same as
int i = 0,j= 0;
That is only the variable j is initialized by 0.
And the statement
j = i;
does not make sense.
Also it is unclear whether c denotes a variable or the character 'c'. If you mean the character 'c' then you need to write at least like
if (*str == 'c')
You could define the function for example the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * duplicate_char( const char *s, char c )
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p == c) ++n;
}
char *nouvelle = malloc( strlen( s ) + n + 1 );
if (nouvelle)
{
if (n == 0)
{
strcpy( nouvelle, s );
}
else
{
char *p = nouvelle;
while (*s)
{
*p++ = *s++;
if (p[-1] == c) *p++ = c;
}
*p = '\0';
}
}
return nouvelle;
}
int main( void )
{
char *nouvelle = duplicate_char( "abcdc", 'c' );
if (nouvelle != NULL) puts( nouvelle );
free( nouvelle );
}
The program output is
abccdcc
If you want to use your own function stringLength instead of the standard C function strlen then it can look like
size_t stringLength( const char *s )
{
const char *p = s;
while ( *p ) ++p;
return p - s;
}
While compiling this below given code, I got the error: lvalue required as left operand of assignment for both the statements str+i = str+((len-1)-i); and str+((len-1)-i) = temp;.
Why?
char* str_reverse(char *str, int len)
{
char *temp;
int i, mid;
if(len%2 == 0)
{
mid = len/2 - 1;
}
else
{
mid = (len-1)/2;
}
for(i=0;i<mid;i++)
{
temp = str+i;
str+i = str+((len-1)-i);
str+((len-1)-i) = temp;
}
return str;
}
str is an lvalue because it is a place in memory which contains an address.
str+i is only an rvalue because it is only an address
Expressions like this
str + i
are rvalues. They can not be assigned. It is the same as to write
int x = 10;
int y = 20;
x + y = 30;
But in any case your function is in essence incorrect. You need to swap characters instead of trying to swap pointer expressions.
Also this if statement
if(len%2 == 0)
{
mid = len/2 - 1;
}
else
{
mid = (len-1)/2;
}
does not make a great sense because the result of the expression
len / 2
is the same whether len is an even number or the following odd number.
For example 2 / 2 is equal to 1 and 3 / 2 is also equal to 1.
Using pointers within the function it can be defined the following way
char * str_reverse( char *str, size_t len )
{
if ( len != 0 )
{
for ( char *left = str, *right = str + len; left < --right; ++left )
{
char c = *left;
*left = *right;
*right = c;
}
}
return str;
}
Use size_t for string lengths.
You are overcomplicating this:
char* str_reverse(char *str, size_t len)
{
char temp, *start = str, *end = str + len -1;
if(str && *str)
{
while(start < end)
{
temp = *start;
*start++ = *end;
*end-- = temp;
}
}
return str;
}
I have assignment that to use function char *slova(const char *s) which returns dynamically allocated string that is only made of small and big letters. It's forbidden to use string.h library.
char *slova(const char *s)
{
char *new;
int br = 0;
new = (char *)malloc(sizeof(s));
for (int i = 0; i != '\0'; i++)
if(s[i] >= 'A' && s[i] <= 'z')
{
new[br] = s[i];
br++;
}
return new;
}
I know there are some other characters other than small and big letters between A and z in ASCII code, so don't worry about that. For some reason this code doesn't work and I don't know why.
sizeof(s) will return not the buffer size but the size of the pointer s.
i != '\0' is wrong. This means i != 0 and prevent it from entering the loop because initial value of i is 0.
You forgot to terminate the resulting string by adding a terminating null-character.
Casting the result of malloc() in C is discouraged.
Fixed code:
char *slova(const char *s){
char *new;
int br = 0;
// calculate the length
for (int i = 0; s[i] != '\0'; i++)
if(s[i] >= 'A' && s[i] <= 'z'){
br++;
}
// allocate buffer
new = malloc(br + 1);
if (new == NULL) return NULL;
// actually create the string
br = 0;
for (int i = 0; s[i] != '\0'; i++)
if(s[i] >= 'A' && s[i] <= 'z'){
new[br] = s[i];
br++;
}
new[br] = '\0';
return new;
}
Look carefully at your function declaration
char *slova(const char *s){
^^^^^^^^^^^^^
Its parameter has the pointer type const char *. Thus in this statement
new = (char *)malloc(sizeof(s));
the expression sizeof(s) yields the size of a pointer that usually is equal to 8 or 4 bytes depending on the used system. That is this expression does not provide the length of the passed string.
Also the body of this loop
for (int i = 0; i != '\0'; i++)
never gets the control because the condition i != '\0' at once evaluates to false because the variable i was initialized by zero.
The function can look the following way as it is shown in the demonstrative program below. It does not use functions from the header <string.h>.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
char * slova( const char *s )
{
size_t n = 0;
for ( const char *t = s; *t != '\0'; ++t )
{
if ( isalpha( ( unsigned char )*t ) ) ++n;
}
char * result = malloc( ( n + 1 ) *sizeof( char ) );
if ( result != NULL )
{
char *p = result;
for ( ; *s; ++s)
{
if ( isalpha( ( unsigned char )*s ) )
{
*p++ = *s;
}
}
*p = '\0';
}
return result;
}
int main(void)
{
const char *s = "H#e#l#l#o W#o#r#l#d";
char *p = slova( s );
if ( p ) puts( p );
free( p );
return 0;
}
The program output is
HelloWorld
If you are not allowed also to use functions from the header <ctype.h> then the function can look the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
char * slova( const char *s )
{
const char *upper_case = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char *lower_case = "abcdefghijklmnopqrstuvwxyz";
size_t n = 0;
for ( const char *t = s; *t != '\0'; ++t )
{
const char *letter = lower_case;
if ( *t < lower_case[0] )
{
letter = upper_case;
}
while ( *letter && *letter < *t ) ++letter;
if ( *letter == *t ) ++n;
}
char * result = malloc( ( n + 1 ) *sizeof( char ) );
if ( result != NULL )
{
char *p = result;
for ( ; *s; ++s)
{
const char *letter = lower_case;
if ( *s < lower_case[0] )
{
letter = upper_case;
}
while ( *letter && *letter < *s ) ++letter;
if ( *letter == *s )
{
*p++ = *s;
}
}
*p = '\0';
}
return result;
}
int main(void)
{
const char *s = "H#e#l#l#o W#o#r#l#d";
char *p = slova( s );
if ( p ) puts( p );
free( p );
return 0;
}
Again the program output is
HelloWorld
I need to replace several characters with one (depending if their count is even or odd). If it's even i should replace + with P, if it's odd with p.
Input: kjlz++zux+++
while(p[i])
{
j=i;
k=i;
length=strlen(p);
if(p[i]=='*')
{
position=i;
}
printf("Position is: %d", position);
while(p[j]=='*')
{
counter++;
j++;
}
}
Output: kjlzPzuxp
Im not sure how to remove several characters I know how to input one.
Basically you can leave the text variable intact until you find a +. In that case you start counting how many consecutive plusses there are. Once you know this, it can be decided if you should add a letter P or p. Keep a separate index to write back to your text variable! Otherwise it would start writing to the wrong index after 2 or 3 plusses are found, try to figure out why ;).
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
char text[] = "kjlz++zux+++";
int len = sizeof(text) / sizeof(text[0]);
int index = 0, count = 0;
for(int i = 0; i < len; i++)
{
if(text[i] == '+')
{
count = 0;
while(text[i] == '+') i++, count++;
i--;
text[index++] = count % 2 ? 'p' : 'P';
}
else
{
text[index++] = text[i];
}
}
text[index] = 0;
printf(text);
}
You could allocate space for the text variable with malloc so that you can use realloc afterwards to shrink the array to the size of the output text. This way some memory is saved, this is especially important when you start working with bigger chunks of data.
If I have understood correctly you do not know how to implement a corresponding function.
It can look the following way as it is shown in the demonstrative program.
#include <stdio.h>
char * replace_pluses( char *s )
{
const char plus = '+';
const char odd_plus = 'p';
const char even_plus = 'P';
char *dsn = s;
for ( char *src = s; *src; )
{
if ( *src == plus )
{
int odd = 1;
while ( *++src == plus ) odd ^= 1;
*dsn++ = odd ? odd_plus : even_plus;
}
else
{
if ( dsn != src ) *dsn = *src;
++dsn;
++src;
}
}
*dsn = '\0';
return s;
}
int main(void)
{
char s[] = "kjlz++zux+++";
puts( s );
puts( replace_pluses( s ) );
return 0;
}
The program output is
kjlz++zux+++
kjlzPzuxp
Or you can write a more generic function like this
#include <stdio.h>
char * replace_odd_even_duplicates( char *s, char c1, char c2, char c3 )
{
char *dsn = s;
for ( char *src = s; *src; )
{
if ( *src == c1 )
{
int odd = 1;
while ( *++src == c1 ) odd ^= 1;
*dsn++ = odd ? c2 : c3;
}
else
{
if ( dsn != src ) *dsn = *src;
++dsn;
++src;
}
}
*dsn = '\0';
return s;
}
int main(void)
{
char s[] = "kjlz++zux+++";
puts( s );
puts( replace_odd_even_duplicates( s, '+', 'p', 'P' ) );
return 0;
}