Recreate strrchr() but getting extra characters at the end of string - c

A task I have is to recreate the function strrchr. I figured out a way to iterate backward from the input given and stopping at the character I need to stop at, but the string came out backwards obviously. I already had created a function to reverse a string so I used that to reverse it back to normal. It works, but somewhere in my while loop when stopping at the character, it adds extra characters. Please help! I don't understand why!
#include <stdio.h>
#include <string.h>
// #include <stddef.h>
int
main () {
char* my_strrchr(char* param_1, char param_2)
{
int i = strlen(param_1) - 1;
int q = 0;
char new[strlen(param_1)];
char *new_ptr = new;
while (i >= 0) {
new[q] = param_1[i];
printf("%c\n", new[q]);
if (param_1[i] == param_2) {
i = 0;
}
i--;
q++;
}
int size = strlen(new_ptr) - 1;
for (int i = 0, q = size; i < q; i++, q--) {
char temp = new_ptr[i];
new_ptr[i] = new_ptr[q];
new_ptr[q] = temp;
}
printf("%s", new_ptr);
return (char *)new_ptr;
}
char *phrase = "C Language is HARD.";
char c = 'g';
my_strrchr(phrase, c);
return 0;
}

You don't need to do anything fancy. Just walk the string from the beginning, updating a variable with the address of the character you're looking for every time it's found, and return it when you hit the end of the string (Unlike strchr(), where you return after the first match). That way you only need one pass through the string instead of the two times it takes if you first find the length and then go backwards.
#include <stdio.h>
#include <stdlib.h>
// Really should return a const char*. Silly standard.
char *my_strrchr(const char *s, int c) {
const char *pos = NULL;
while (*s) {
if ((unsigned char)*s == (unsigned char)c) pos = s;
s++;
}
if (c == 0) {
// If searching for '\0', return a pointer to the one
// at the end of the string
return (char *)s;
} else {
return (char *)pos;
}
}
int main(void){
const char *foo = "the quite wet duck quacks a lot";
puts(my_strrchr(foo, 'q'));
return 0;
}

Related

Is there an easy way to remove specific chars from a char*?

char * deleteChars = "\"\'.“”‘’?:;-,—*($%)! \t\n\x0A\r"
I have this and i'm trying to remove any of these from a given char*. I'm not sure how I would go about comparing a char* to it.
For example if the char* is equal to "hello," how would I go about removing that comma with my deleteChars?
So far I have
void removeChar(char*p, char*delim){
char*holder = p;
while(*p){
if(!(*p==*delim++)){
*holder++=*p;
p++;
}
}
*holder = '\0';
A simple one-by-one approach:
You can use strchr to decide if the character is present in the deletion set. You then assign back into the buffer at the next unassigned position, only if not a filtered character.
It might be easier to understand this using two indices, instead of using pointer arithmetic.
#include <stdio.h>
#include <string.h>
void remove_characters(char *from, const char *set)
{
size_t i = 0, j = 0;
while (from[i]) {
if (!strchr(set, from[i]))
from[j++] = from[i];
i++;
}
from[j] = 0;
}
int main(void) {
const char *del = "\"\'.“”‘’?:;-,—*($%)! \t\n\x0A\r";
char buf[] = "hello, world!";
remove_characters(buf, del);
puts(buf);
}
stdout:
hello world
If you've several delimiters/characters to ignore, it's better to use a look-up table.
void remove_chars (char* str, const char* delims)
{
if (!str || !delims) return;
char* ans = str;
int dlt[256] = {0};
while (*delims)
dlt[(unsigned char)*delims++] = 1;
while (*str) {
if (dlt[(unsigned char)*str])
++str; // skip it
else //if (str != ans)
*ans++ = *str++;
}
*ans = '\0';
}
You could do a double loop, but depending on what you want to treat, it might not be ideal. And since you are FOR SURE shrinking the string you don't need to malloc (provided it was already malloced). I'd initialize a table like this.
#include <string.h>
...
char del[256];
memset(del, 0, 256 * sizeof(char));
for (int i = 0; deleteChars[i]; i++) del[deleteChars[i]] = 1;
Then in a function:
void delChars(char *del, char *string) {
int i, offset;
for (i = 0, offset = 0; string[i]; i++) {
string[i - offset] = string[i];
if (del[string[i]]) offset++;
}
string[i - offset] = 0;
}
This will not work on string literals (that you initialize with char* x = "") though because you'd end up writing in program memory, and probably segfault. I'm sure you can tweak it if that's your need. (Just do something like char *newString = malloc(strlen(string) + 1); newString[i - offset] = string[i])
Apply strchr(delim, p[i]) to each element in p[].
Let us take advantage that strchr(delim, 0) always returns a non-NULL pointer to eliminate the the null character test for every interrelation.
void removeChar(char *p, char *delim) {
size_t out = 0;
for (size_t in; /* empty */; in++) {
// p[in] in the delim set?
if (strchr(delim, p[in])) {
if (p[in] == '\0') {
break;
}
} else {
p[out++] = p[in];
}
}
p[out] = '\0';
}
Variation on #Oka good answer.
it is better way - return the string without needless characters
#include <string.h>
char * remove_chars(char * str, const char * delim) {
for ( char * p = strpbrk(str, delim); p; p = strpbrk(p, delim) )
memmove(p, p + 1, strlen(p));
return str;
}

Reverse a string recursively in C - using a pointer to string only

i'm trying to reverse a string using recursion and a single pointer to that string.
My idea is to traverse the string from both edges, raising the pointer and inserting '\0's at the end of the string. For example - given a string 'abcde\0' - replace "chars" before the middle of the string, and insert '\0' after -> recursive calls -> when "stop condition" is reached, original string should be like this - 'edc\0\0\0' - and half of chars stored as temp variable, in stack. When turning back and popping the stack, these chars should overwrite the '\0' in reverse order. This is the idea.
This is my code so far, but I can't get it work - please help me understand, what do I miss. I have a '\0' in the middle of string that I can't figure out how to rewrite it. (I guess this is the major problem)
Thanks in advance.
#include <stdio.h>
#include <string.h>
void rev_str(char* _str);
int main()
{
char str[]="abcde";
puts("Str before:");
puts(str);
rev_str(str);
puts("Str after");
puts(str);
return 0;
}
void rev_str(char* _str)
{
int len=strlen(_str);
char temp=*_str;
if(len>1)
{
*_str = _str[len-1];
_str[len-1]='\0';
rev_str(++_str);
}
_str[len-1]=temp;
}
I won't debug your code, however this might help you understand things better -
http://www.programmingsimplified.com/c-program-reverse-string
Examples taken from page -
C program to reverse a string using pointers
Now we will invert string using pointers or without using library function strrev.
#include<stdio.h>
int string_length(char*);
void reverse(char*);
main()
{
char string[100];
printf("Enter a string\n");
gets(string);
reverse(string);
printf("Reverse of entered string is \"%s\".\n", string);
return 0;
}
void reverse(char *string)
{
int length, c;
char *begin, *end, temp;
length = string_length(string);
begin = string;
end = string;
for (c = 0; c < length - 1; c++)
end++;
for (c = 0; c < length/2; c++)
{
temp = *end;
*end = *begin;
*begin = temp;
begin++;
end--;
}
}
int string_length(char *pointer)
{
int c = 0;
while( *(pointer + c) != '\0' )
c++;
return c;
}
C program to reverse a string using recursion
#include <stdio.h>
#include <string.h>
void reverse(char*, int, int);
int main()
{
char a[100];
gets(a);
reverse(a, 0, strlen(a)-1);
printf("%s\n",a);
return 0;
}
void reverse(char *x, int begin, int end)
{
char c;
if (begin >= end)
return;
c = *(x+begin);
*(x+begin) = *(x+end);
*(x+end) = c;
reverse(x, ++begin, --end);
}
rev_str(++_str);
This is the problem. You're modifying _str here so when you do _str[len-1]=temp at the end, you're writing to the wrong location. Change it to
rev_str(_str + 1);
Just change the code rev_str(++_str); into rev_str(_str+1);. The ++_str equal to _str += 1, it will change the pointer char *_str. But _str+1 will only initialize the formal param, and will not change the 'char *str'. I hope this can help you.

Pointer to string not incrementing (C programming)

I have two string shown below:
char code *text_to_compare = "TesT";
char code *dictionary = "TesTT,Tes,Tes,TesT.";
In a part of the program I used the following code where it increments the pointers for both strings to point to the next characters.
ch_A = text_to_compare[i++];
ch_B = dictionary[j++];
Why is pointer j being incremented but pointer i is remaining as it was?
Thanks in advance.
EDIT: Below is the full code. The aim of this project is to compare a string with a list of words. Integer i is not incrementing only after the program enters the else statement.
#include <string.h>
char code *text_to_compare = "TesT";
char code *dictionary = "TesTT,Tes,Tes,TesT.";
int bring_characters(char pdata *, char pdata *, char ch_A, char ch_B, char i,
char j);
void main(void) {
unsigned char ch_A;
unsigned char ch_B;
unsigned char i = 0;
unsigned char j = 0;
char pdata N1;
char pdata N2;
int result;
ch_A = text_to_compare[i]; // take a caharacter from the text
ch_B = dictionary[j];
result = bring_characters(&N1, &N2, ch_A, ch_B, i, j);
if (result == 0) {
while (1)
;
}
else {
while (1)
;
}
while (1)
;
}
int bring_characters(char pdata *N1, char pdata *N2, char ch_A, char ch_B,
char i, char j) {
do {
if (ch_A == ch_B) {
ch_A = text_to_compare[i++]; // take a caharacter from the text
ch_B = dictionary[j++];
if ((ch_A == '\0') && ((ch_B == ',') || (ch_B == '.'))) {
while (1)
; // load idata-------------------------------------------------------------------------------------------------
}
}
else {
i = 0; // refresh pointer
ch_A = text_to_compare[i]; // take a caharacter from the text
ch_B = dictionary[j++];
}
} while (ch_B != '.');
return (0);
}
Whew, there's a lot going on here! Now that you've added the full code it looks like in your attempt to move on to the next word you have prevented yourself from moving on.. you'll need to do some major revisions to get this guy working.
The first thing you need to do is figure out how you would do this on paper, then step by step try to reproduce that in your code.
Here's a function to kickstart you:
int find_next_match(char toFind, int startingPosition, char* mainString){
int counter = startingPosition;
char buf = mainString[counter];
while(buf != NULL){
if (buf == toFind){
return counter;
}
counter++;
buf = mainString[counter];
}
return -1; //error
}
You can use something like this to find the next instance of the first character in your string, then you can implement a loop to determine if that is a match.
Good luck, you can do it!

pointer substrings arrays

Im trying to copy part of a string to another string using pointers. My resulting string starts to copy at the correct place though it doesn't stop after exceeding the count. Also the string isn't copy from the source string rather than from the result parameter
#include <stdio.h>
char *getSub(const char *orig, int start, int count, char *res);
int main(void)
{
const char orig[] = "one two three";
char res[] = "123456789012345678";
printf("%s\n",getSub(orig, 4, 3, res));
return 0;
}
char *getSub(const char *orig, int start, int count, char *res)
{
const char *sCopy = orig;
while (*orig)
{
if (start >= (orig - sCopy)) && (res-sCopy < count))
{
*res++ = *orig++;
}
else
*orig++;
}
return res;
}
The big mistake is that you're calculating the difference of two unrelated pointers, res - sCopy (I suppose sourceCopy is also sCopy in the real code, or the other way round). Calculating the difference of pointers is only meaningful if both pointers point into (or one past the end of) the same array. As written, whether anything gets copied at all depends on the arbitrary locations of the two arrays.
if (start >= (orig - sourceCopy)) && (res-sCopy < c))
{
*res++ = *orig++;
}
else
*orig++;
anyway, that doesn't count how many characters are copied if any are copied at all.
Another mistake is that you don't 0-terminate the copy.
A correct implementation would be
char *getSub(const char *orig, int start, int count, char *res)
{
char *from = orig, *to = res;
// check whether the starting position is within orig
for( ; start > 0; --start, ++from)
{
if (*from == 0)
{
res[0] = 0;
return res;
}
}
// copy up to count characters from from to to
for( ; count > 0 && *from; --count)
{
*to++ = *from++;
}
// 0-terminate
*to = 0;
// return start of copy, change to return to if end should be returned
return res;
}
There are at least two problems with your code.
res - sCopy makes no sense because they are pointing at different objects.
You haven't null-terminated the destination string.
#include <string.h>
char *getSub(const char *orig, int start, int count, char *res){
int i,j,len = strlen(orig), limit = start + count;
if(res == NULL) return NULL;
if(start >= len || start < 0 || orig == NULL){
*res = '\0';
return res;
}
for(j=0,i=start;i<len && i < limit;++i){
res[j++]=orig[i];
}
res[j]='\0';
return res;
}

Null terminating char pointer

I am completely newbie in C.
I am trying to do simple C function that will split string (char array).
The following code doesn't work properly because I don't know how to terminate char array in the array. There are to char pointers passed in function. One containing original constant char array to be split and other pointer is multidimensional array that will store each split part in separate char array.
Doing the function I encountered obviously lots of hustle, mainly due to my lack of C experience.
I think what I cannot achieve in this function is terminating individual array with '\0'.
Here is the code:
void splitNameCode(char *code, char *output);
void splitNameCode(char *code, char *output){
int OS = 0; //output string number
int loop;
size_t s = 1;
for (loop = 0; code[loop]; loop++){
if (code[loop] == ':'){
output[OS] = '\0'; // I want to terminate each array in the array
OS ++;
}else {
if (!output[OS]) {
strncpy(&output[OS], &code[loop], s);
}else {
strncat(&output[OS], &code[loop], s);
}
}
}
}
int main (int argc, const char * argv[]) {
char output[3][15];
char str[] = "andy:james:john:amy";
splitNameCode(str, *output);
for (int loop = 0; loop<4; loop++) {
printf("%s\n", output[loop]);
}
return 0;
}
Here is a working program for you. Let me know if you need any explanation.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void splitNameCode(char *code, char **output) {
int i = 0;
char* token = strtok(code, ":");
while (token != NULL) {
output[i++] = token;
token = strtok(NULL, ":");
}
}
int main (int argc, const char *argv[]) {
char* output[4];
char input[] = "andy:james:john:amy";
splitNameCode(input, output);
for (int i = 0; i < 4; i++) {
printf("%s\n", output[i]);
}
return 0;
}
If I understand your intent correctly, you are trying to take a string like andy:james:john:amy and arrive at andy\0james\0john\0amy. If this is the case, then your code can be simplified significantly:
void splitNameCode(char *code, char *output){
int loop;
strncpy(code, output, strlen(code));
for (loop = 0; output[loop]; loop++){
if (output[loop] == ':'){
output[loop] = '\0'; // I want to terminate each array in the array
}
}
}

Resources