Make own strrchr() function but case-insensitiv
my exercise is to create my own strrchr() function in c.
My solution is a loop. I'am counting the array length. I will input this number into the for loop. For example: With the input Hello. I will go from right to left to search for a letter.
What's not working is the return part.
My code returns the following with the input Hello, and search letter l. lo. That's not what I need. My ouput should be lleH.
Any ideas what I did wrong?
char *KULstrrcichr(char *arr, char search)
// The strrchr() function returns a pointer to the last occurrence of the character c in the string s.
{
int stringcnt;
stringcnt = strlen(arr);
printf("%d\n", stringcnt);
search = tolower(search);
for (int i = stringcnt-1; arr[i]; i--)
{
arr[i] = tolower(arr[i]);
}
for (int i = stringcnt-1; arr[i]; i--)
{
if (search == arr[i])
{
return &arr[i];
}
}
return 0;
}
Okay I found out that my code works as expected...
1 answer
-
answered 2022-05-04 11:35
Vlad from Moscow
The standard C function
strrchr
is declared the following waychar *strrchr(const char *s, int c);
That is it first parameter has the qualifier
const
and the second parameter is of the typeint
. It means that you may not change the source string.Also this for loop
for (int i = stringcnt-1; arr[i]; i--)
invokes undefined behavior due to the incorrect condition.
The function can be defined the following way as shown in the demonstration program below.
#include <string.h> #include <stdio.h> #include <ctype.h> char * my_strrchr( const char *s, int c ) { c = tolower( ( unsigned char )c ); const char *p = s + strlen( s ) + 1; while (p != s && tolower( ( unsigned char )p[-1] ) != c) --p; return p == s ? NULL : ( char * )( p - 1 ); } int main( void ) { char s[] = "helLo"; char *p = my_strrchr( s, 'l' ); if (p != NULL) { printf( "position = %td, substring = %s\n", p - s, p ); } }
The program output is
position = 3, substring = Lo
do you know?
how many words do you know
See also questions close to this topic
-
How do I manipulate the contents of a stat() struct?
I have a stat struct, and I'm looking for a way to get data out of it to be manipulated. The program will successfully run and print the desired st_mtime value, but including either of the "seg-fault" lines below causes a segmentation fault in runtime.
struct stat buf; time_t time_m; time_t sys_time = time(0); if(stat(sub_dirp->d_name,&buf)==0) { //time_m = buf.st_mtime; //seg-fault //double since_last = (difftime(sys_time, buf.st_mtime)/60); //seg-fault printf("%d ", (int)buf.st_mtime); //This works. }
Both lines are attempting to manipulate the
buf.st_mtime
value in some way.I've had a hard time finding any examples of the usage of stat() that do anything other than print its contents, which makes me wonder if it's even possible.
So my question is, if it is possible, what am I missing?
P.S. I do wish to keep
st_mtime
in the Unix timestamp format to make it easier to manipulate.Edit: After realizing that
st_mtime
is itself its own struct (timespec), how can I access thest_mtime.tv_sec
member?The compiler doesn't like
buf.st_mtime.tv_sec
one bit. -
What's purpose of __linecapp in getline, when it'll auto resize?
It's all about second parameter of getline in stdio.h,
I'll name it 'n' or '__linecapp' below.
According to the document:
If the buffer is not large enough to hold the line, getline() resizes it with realloc(3), updating *lineptr and *n as necessary.
It'll automatically update line capacity, then why should we input __linecapp?
P.S Someone ask before, but discussion didn't explain when we need it, or how to make it useful.
-
Linked List Deletion function causing program to crash *wrong pointers?*
In my program when a username is following another one and also has posted a "tweet" which is a string in an attempt to delete the followed username it breaks the program. I believe this is the code snippet in question. If anyone could help me identify the issue I would be thankful as I am learning the usage of linked lists for scale able projects. Thanks
void deleteAccount(accountNodePtr *startPtr, accountNodePtr *curAcPtr, tweetsNodePtr *startTwtPtr){ accountNodePtr acLoopPtr; accountNodePtr tempCur = *curAcPtr; followNodePtr followingPtr = tempCur->followingPtr; followNodePtr tempPtr; followNodePtr tempPtr2; tweetsNodePtr iterTwtPtr; iterTwtPtr = *startTwtPtr; *below here in question* tempCur = *curAcPtr; while (tempCur->followersPtr!=NULL){ acLoopPtr = *startPtr; while (strcmp(acLoopPtr->username, tempCur->followersPtr->username)!=0){ acLoopPtr=acLoopPtr->nextPtr; } if (strcmp(acLoopPtr->followingPtr->username, tempCur->username)==0){ tempPtr=acLoopPtr->followingPtr->nextPtr; free(acLoopPtr->followingPtr); acLoopPtr->followingPtr=tempPtr; }else{ tempPtr=acLoopPtr->followingPtr; while(strcmp(tempPtr->nextPtr->username, tempCur->username)!=0){ tempPtr=tempPtr->nextPtr; } tempPtr2=tempPtr->nextPtr->nextPtr; free(tempPtr->nextPtr); tempPtr->nextPtr=tempPtr2; } tempPtr = tempCur->followersPtr->nextPtr; free(tempCur->followersPtr); tempCur->followersPtr=tempPtr; }
This is the structure
typedef struct followsNode { char username[MAX_USERNAME]; struct followsNode *nextPtr; } followNode; typedef struct accountsNode { char username[MAX_USERNAME]; struct followsNode *followersPtr; struct followsNode *followingPtr; struct accountsNode *nextPtr; } accountNode; typedef followNode *followNodePtr; typedef accountNode *accountNodePtr;
-
After using .NET upgrade assistant on C# solution, why does .StartsWith give a false positive?
I updated my solution from .NET 4.8 to 6.0 and it builds and runs fine after fixing references, but now using StartsWith with chars gives an unexpected result.
A string that starts with the chars \0\0\0 evaluates as True when using:
example.StartsWith(new string(new char[] {'\u0003', '\u0005', '\0'}));
From what I've seen maybe this has to do with culture? Do I need to make a new StartsWith function that compares each character one at a time? example[0] == '\u0003' is still obviously False.
-
How do you check if the user input is a single Char
I'm trying to write a program where if the user enters a single character, the program displays True on screen, otherwise if multiple characters are entered it prints False.
public class FinalExamTakeHome8 { public static void main(String[] args) { try (Scanner kbd = new Scanner(System.in)) { System.out.println("Enter an item"); if (kbd.hasNextInt() || kbd.hasNextChar() || kbd.hasNextDouble()) { System.out.println("True"); } else { System.out.println("False"); } } } }
-
No suitable function from string to char exists
I'm fairly new to C++ and have been messing around with classes lately. In my problem I need to take in the ticket name and number and make functions that tell the user if the seat is available or not. If it is not available, the seat can be booked and needs to be stored. To solve this problem, I created a dynamic array that takes in the seat information and grows by length everytime a seat has been booked. Since this array takes in strings, I also defined it as a string. However, when I try to store in the seats and row names, I get an error that says that a string cannot be converted to a char. I tried to change the array to char type but that did not do the trick. Below I have added my code (sorry it's some what lengthy) with explanation. Hopefully I have provided you with enough info, thanks a lot!
#include <iostream> #include <string> #include <cstring> using namespace std; //Initializing Ticket class class ShowTicket{ public: //Defining variables string row; string seatNumber; bool sold; //true or false statement if the seat is available or not string status; int size; string *arr = new string[size,2]; int *newSize = &size; //pointer that points to size and changes +1 length if //seat gets booked //Constructor ShowTicket(string rows, string seatNumbers){ row = rows; seatNumber = seatNumbers; sold = false; //Seat is available by default untill it gets booked status = "available"; //printing that the seat is available by default, untill //it gets booked string *arr = new string[size,2]; //2D dynamic array that grows in size and //stores seat number and row } bool isSold(string row, string seat); //function taking in row and seat and checks //if the seat is available void sell_seat(string row, string seat); //function that sells a seat and stores it //in arr string print_ticket(string row, string seat);//function to print the ticket info }; bool ShowTicket::isSold(string rows, string seats){ for(int i; i<= size; i++){ //for loop to loop over each element of the array if (arr[i][0] != rows && arr[i][1] != seats){//check if each element matches //with a sold ticket, if not it //returns sold = false return sold; } } } void ShowTicket::sell_seat(string row, string seat){ //This function adds 1 element to //to pointer array to store in new //data *newSize = size+ 1; //new size is initialized and with that size is incremented by //+1 string *temp = new string[newSize,2]; //temporary array is created with the new size for(int i; i <size; i++){ temp[i] = arr[i]; //temporary array copies data from array } delete [] arr; // old pointer array is deleted to avoid memory leaks arr = temp; //array is pointing to array with +1 length arr[*newSize][0] = row; //new ticket info is stored in the newly created space arr[*newSize][1] = seat; //^^ sold = true; //giving info that the ticket is indeed sold status = "sold"; //when calling the function, it now also prints the ticket is //stored } string ShowTicket::print_ticket(string row, string seat){ string a = ""; cout << row << " " << seatNumber << " " << status; //printing ticket info return a; } int main(){ ShowTicket myticket1("AA","101"); //creating tickets with input ShowTicket myticket2("AA","102"); ShowTicket myticket3("BB","103"); if(!myticket1.isSold()){//checking if the ticket is already sold myticket1.sell_seat();//if not, it is bought } cout << myticket1.print_ticket() << endl; //printing ticket information cout << myticket2.print_ticket() << endl; cout << myticket3.print_ticket() << endl; return 0; }
-
Difference between " %[^\n]%*c" and " %[^\n]" for consecutive scanf in C
I've been trying to scanf multiple consecutive strings.
I know you have to eliminate the newline character and i've also been told that "%[^\n]%*c" is the RIGHT way. But in my tests, " %[^\n]" works even better because it's simpler and also doesn't go wrong if i try to feed it a newline directly, it keeps waiting a string. So far so good.
Is there any case in which "%[^\n]%*c" is the better way?
Thanks a lot!
-
Make own strchr() function but case-insensitive
My exercise requires that I can use case-insensitive input. My approch is that I use the tolower and toupper function.
How can I convert the array to lowercase letters?
void KULstrcichr(char *arr, char search) { printf("Return value when uppercase character %c is passed to isupper(): %d\n", search, isupper(search)); // The strchr() function returns a pointer to the first occurrence of the character c in the string s. if (isupper(search)) { printf("Groß\n"); char lowercasesearch = tolower(search); printf("Das ist der Output: %s", arr); char *ptr = strchr(arr, lowercasesearch); printf("Das ist der Buchstabe: %s", ptr); } else { printf("Klein\n"); char upercasesearch = toupper(search); printf("Das ist der Output: %s", arr); char *ptr = strchr(arr, upercasesearch); printf("Das ist der Buchstabe: %s", ptr); } }
-
find elements of an array in another array, why do I have this error?
I was trying to visualize the algorithm of this exercise, but I'm having a lot of problems.
the exercise asks to implement this function:
extern const void *memmem(const void *haystack, size_t hsize, const void *needle, size_t nsize);
- haystack and needle are two pointers to two different areas of memory. haystack points to a memory of size hsize, and needle points to a memory of size nsize.
- find *needle elements in *haystack, and if *needle elements are in *haystack too, return a pointer to the new allocated memory (containing *needle elements) and this pointer has to point to the 0-th element of the new memory.
I hope I've explained it better than the original exercise (it's not clear, so I had a hard time trying to understand it).
I've tried to sketch the algorithm this way:
algorithm accepts two pointers and their sizes. (loop) increment *needle by one at each step in order to find a common element (comparing that element with the current element of haystack), and if that condition is true, increment a counter by one. Doing this way I've obtained the length of the final array. Then, I allocate enough memory, and do another loop to copy each element in the final vector. last but not least, return this pointer.
this is how is it suppose to look like in code (I know it's not complete, but I'm currently building it step by step, it's not easy at all):
#include <stdlib.h> const void* memmem(const void* haystack, size_t hsize, const void* needle, size_t nsize) { if ((hsize == 0) || (nsize = 0)) { return NULL; // here, I should've done a NULL pointer exception check too, because haystack and needle may be null pointer too. for now, ignore that. } for (size_t i = 0; i < nsize; i++) { if (needle[i] == haystack[i]) } } int main(void) { int haystack[] = {-1, 0, 1, 2, 3, 4}; size_t hsize = 6; int needle[] = {-1, 8, 4, 2}; size_t nsize = 4; int* ptr = memmem(haystack, hsize, needle, nsize); return 0; }
the crucial part is here:
for (size_t i = 0; i < nsize; i++) { if (needle[i] == haystack[i]) }
because I have this error: expression must be a pointer to a complete object type. What does it mean? I've never heard of this error message before. arrays are complete, I've defined them correctly, therefore I don't know why I have that.
-
Is it right to implement queue with single linked list?
My Code ↓
Some macros defined by
#include <stdio.h> #include <malloc.h> #define ElementType int #define ERROR 0 // 队列用单链表实现 struct Node { ElementType Data; struct Node *Next; }; struct QNode { struct Node *rear; struct Node *front; }; typedef struct QNode *Queue;
Add an element to the end of the queue
void AddQ(Queue PtrQ, ElementType item) { struct Node *rearCell; rearCell = (struct Node *) malloc(sizeof(struct Node)); rearCell->Data = item; rearCell->Next = NULL; if (PtrQ->front == PtrQ->rear && PtrQ->rear == NULL) { PtrQ->front = PtrQ->rear = rearCell; } else { PtrQ->rear->Next = rearCell; PtrQ->rear = rearCell; } }
Delete the element from the beginning of the queue and return the element value.
ElementType DeleteQ(Queue PtrQ) { struct Node *FrontCell; ElementType FrontElement; if (PtrQ->front == NULL) { printf("队列空"); return ERROR; } FrontCell = PtrQ->front; if (PtrQ->front == PtrQ->rear) PtrQ->front = PtrQ->rear = NULL; else PtrQ->front = PtrQ->front->Next; FrontElement = FrontCell->Data; free(FrontCell); return FrontElement; }
Initializing queues and calling
int main() { Queue PtrQ = (Queue) malloc(sizeof(struct QNode)); PtrQ->front = NULL; PtrQ->rear = NULL; AddQ(PtrQ, 999); AddQ(PtrQ, 88); AddQ(PtrQ, 77); ElementType value = DeleteQ(PtrQ); printf("%d\n", value); ElementType value1 = DeleteQ(PtrQ); printf("%d\n", value1); ElementType value2 = DeleteQ(PtrQ); printf("%d\n", value2); return 0; }
It worked out as I expected.
question
if (ptrq-> front = = ptrq-> rear & & ptrq-> rear = = null)
in AddQ. Is there a better judgment? and some other improvementsI'm learning to implement queues in C.
-
Why this function is not able to reverse the Linked List?
I want to reverse a linked list but when i compile this code it terminates unexpectedly.
#include <bits/stdc++.h> using namespace std; class node{ public: int data; node* next; node(int val){ data=val; next=NULL; } };
For Inserting Elements in Linked List
void insertattail(node* &head,int lol){ node* n= new node(lol); if(head==NULL){ head=n; return; } node* temp=head; while(temp->next!=NULL){ temp=temp->next; } temp->next=n; }
Display Function to print linked list
void display(node* head){ node* temp =head; do{ cout<<temp->data<<"->"; temp=temp->next; } while(temp!=NULL); cout<<"Null"; }
Function to reverse Linked List
node* reverseit(node* head){ node* prevptr= NULL; node* currptr= head; node* nextptr= currptr->next; while(currptr!=NULL){ currptr->next =prevptr; prevptr=currptr; currptr=nextptr; nextptr=currptr->next; } return prevptr; }
Main Function
int main() { node* head= NULL; insertattail(head,1); insertattail(head,2); insertattail(head,3); insertattail(head,8); node* newhead= reverseit(head); display(newhead); return 0; }
I think the problem is in logic of reverse function. I just used the code for linked list and made small changes.
-
Is there a caseinsensitive version of strrchr and wcsrchr?(c++)
I try to check if
variable
ends withexpression
.My current code is this:
(strchr(variable.data(), tolower(expression[0])) || strchr(variable.data(), toupper(expression[0]))) && _stricmp((strrchr(variable.data(), tolower(expression[0]))? strrchr(variable.data(), tolower(expression[0])) : strrchr(variable.data(), toupper(expression[0]))), expression.data()) == 0
It works. But with a case-insensitive version of
strrchr
andstrchr
I can simlpify it. I also need the case-insensitive versions ofwcsrchr
andwcsrchr
for UTF16-strings:(wcschr(variable.data(), tolower(expression[0])) || wcschr(variable.data(), toupper(expression[0]))) && _wcsicmp((wcsrchr(variable.data(), tolower(expression[0])) ? wcsrchr(variable.data(), tolower(expression[0])) : wcsrchr(variable.data(), toupper(expression[0]))), expression.data()) == 0
I´m open for other simplifications.
I can´t write additional methods because the mainprogram is a vs-extension written in c#.
-
why do i get Segmentation fault (core dumped) error here?
while trying to regenerate the function strrchr i get this error, can someone help me understand this part?
#include <stdio.h> char *ft_strrchr(const char *s, int c) { int i; char *ptr; ptr = NULL; i = 0; while (*s) { if (*(s + i) == (const char)c) { ptr = ((char*)(s + i)); } ++i; } return (ptr); } int main() { const char *tx = "test a test a test"; int a = 'a'; char *ptr = ft_strrchr(tx,a); printf("%c",*ptr); return 0;
}