please help making strstr() - c

I have made strstr() function but the program does not give any output,just a blank screen.Please have a look at the code.
#include<stdio.h>
#include<conio.h>
const char* mystrstr(const char *str1, const char *str2);
int main()
{
const char *str1="chal bhai nikal";
const char *str2="nikal",*result;
result=mystrstr(str1,str2);
printf("found at %d location",(int*)*result);
getch();
return 0;
}
const char * mystrstr(const char *s1, const char *s2)
{
int i,j,k,len2,count=0;
char *p;
for(len2=0;*s2!='\0';len2++);//len2 becomes the length of s2
for(i=0,count=0;*s1!='\0';i++)
{
if(*(s1+i)==*s2)
{
for(j=i,k=0;*s2!='\0';j++,k++)
{
if(*(s1+j)==*(s2+i))
count++;
if(count==len2)
{
p=(char*)malloc(sizeof(char*));
*p='i';
return p;
}
}
}
}
return NULL;
}

The line with this comment:
//len2 becomes the length of s2
is broken. You repeatedly check the first character of s2. Instead of *s2, try s2[len2].
Edit: as others have said, there are apparently a lot more things wrong with this implementation. If you want the naive, brute-force strstr algorithm, here's a concise and fast version of it:
char *naive_strstr(const char *h, const char *n)
{
size_t i;
for (i=0; n[i] && h[i]; i++)
for (; n[i] != h[i]; h++) i=0;
return n[i] ? 0 : (char *)h;
}

It looks like this is an exercise you're doing to learn more about algorithms and C strings and pointers, so I won't solve those issues for you, but here are some starting points:
You have an infinite loop when calculating len2 (your loop condition is *s2 but you're never changing s2)
You have a similar issue with the second for loop, although I you have an early return so it might not be infinite, but I doubt the condition is correct
Given you want to behave like strstr(), you should return a pointer to the first string, not a new pointer you allocate. There is no reason for you to allocate during a function like strstr.
In main() if you want to calculate the position of the found string, you want to print result-str1 unless result is NULL). (int*)*result makes no sense - result should be a pointer to the string (or NULL)

You also need to change this line:
if(*(s1+j)==*(s2+i))
to this:
if(*(s1+j)==*(s2+k))
As already mentioned, the return value is a bit odd. You are returning a char* but kind of trying to put an integer value in it. The result doesn't make sense logically. You should either return a pointer to the location where it is found (no malloc needed) or return the integer position (i). But returning the integer position is not the "typical" strstr implementation.

Related

I tried creating a function to concatinate str2 to str1 using pointers but it doesn't work as I am expecting

I was making an strcat using pointers in C, however I encountered the following problem in my while loop.
This is my code which fails to add str2 (here t) to str1 (here s):
char *pstrcat(char *s,char *t)
{
char *start=s;
while(*s++)
;
while(*s++=*t++){
;
}
return start;
}
My main code was:
int main()
{
char s[35]=" hi nice to meet you ";
char t[]="ho";
printf("%s",pstrcat(s,t));
return 0;
}
Expectations:
I was expecting a output of hi nice to meet you ho but instead got hi nice to meet you.
However when I changed the while loop (first while loop of pstrcat) a little bit it started to work.
The new while loop looked like:
while(*s!='\0')
s++;
Problem in brief:
I was unable to understand the difference of the two loops. I think both of them should work since both of them must be ending at '\0' with address of s currently pointing to '\0'.
However I must be wrong if my code isn't working.
There are two problems with the code.
Destination array does not have enough space to accommodate additional chars.
First while loop in pstrcat moves the pointer beyond \0
while(*s++)
;
It can be rewritten as
while(*s)
s++;
You probably don't know if one character array is big enough to fit both strings in so it's safer to create a new one but you must remember to free it after you've done with it. To concatenate two null-terminated strings, you could do the following...
char *pstrcat(char *s,char *t)
{
char *start=malloc(strlen(s) + strlen(t) + 1);
sprintf(start, "%s%s%c", s, t, 0);
return start;
}
int main()
{
char s[]=" hi nice to meet you \0";
char t[]="ho\0";
char *st = pstrcat(s,t);
printf("%s",st);
free(st);
return 0;
}
Thanks to everyone I managed to solve the problem in the following two ways:
char *pstrcat(char *s,char *t)
{
char *start=s;
while(*s++)
;/*in the end when *s=='\0' it is checked in while loop and after checking it is incremented to point at void hence we have to decrement once*/
s--;
while(*s++=*t++){
;
}
return start;
}
char *pstrcat(char *s,char *t)
{
char *start=malloc(strlen(s)+strlen(t)+1);
sprintf(start,"%s%s%c",s,t,0);
return start;
}

The below code runs encryption part well but when 'z' is entered it gives unexpected output and doesnt run decryption part

#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(;i<100;i++)
{
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(;i<100;i++)
{
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
You are returning a pointer to automatic variables en and de which are stored in the stack. This in turn means after returning from the functions encrypt and decrypt their place in the memory can be used by any other variable.
so to correct that, you need to define en and de as static.
const char *encrypt(char *str){
static char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1){
static char de[100];
int i=0;
for(;i<100;i++){
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
Though a more suitable and safer way to implement that would be:
#include<stdio.h>
void encrypt(char *str, char *encStr);
void decrypt(char *str1, char* decStr);
int main()
{
char str[100], encDecStr[100];
//Encryption
printf("Enter String for encryption\n");
scanf("%s", str);
encrypt(str, encDecStr);
printf("%s after encryption is %s\n",str,encDecStr);
//Decryption
printf("Enter String for decryption\n");
scanf("%s", str);
decrypt(str, encDecStr);
printf("%s after decryption is %s",str,encDecStr);
return 0;
}
void encrypt(char *str, char *encStr)
{
for(char *c = str; *c != '\0'; c++)
{
*encStr++ = *c + 1;
}
*encStr='\0';
}
void decrypt(char *str1, char* decStr)
{
for(char *c = str1; *c != '\0'; c++)
{
*decStr++ = *c - 1;
}
*decStr++='\0';
}
Note: The code was not fully tested for different use cases.
There are quite a number of errors in your code:
Returning arrays with local storage duration:
The array's life time ends (i.e. it ceases to exist) as soon as you exit from the function, thus the pointer returned is dangling, reading from it is undefined behaviour
You write beyond the bounds of your local array: en[i] = '\0' with i being 100 after the loop is out of the range of valid indices from 0 to 99, which again is undefined behaviour.
You have differing offsets for encrypting (1) and decrypting (3).
Simply adding an offset without further checks (or modulo operations) will produce different character sets for input and output strings (might be your least problem...).
You always en-/decode the entire array, which is more than actually needed. Additionally the terminating null character then is encoded as well, resulting in different lengths of input and output and garbage at the end of encoded string.
Use of gets is dangerous as it allows a user to write beyond the input array, resulting in undefined behaviour. This is the reason why it actually has been removed from C language with C11 standard – which introduces a safe alternative gets_s. Yet another alternative (especially for pre-C11 code) is fgets.
For the dangling pointer problem there are several options:
Making the array static (as mentioned already):The disadvantage of this approach is that the function is not thread-safe any more. Additionally calling the function more than once overwrites previous results, if you haven't evaluated already or copied them they are lost.
Returning a dynamically allocated array, see malloc function. This comes with the risk of the caller forgetting to free the allocated memory again, which would result in a memory leak
Changing the input array in place: Disadvantage of is having to copy the input into a backup if it is yet needed afterwards.
Letting the caller provide the buffer.
Last option is most flexible and most idiomatic one, so I'll concentrate on this one:
void caesar(char const* input, char* output, int offset)
{
int const NumChars = 'z' - 'a';
offset = offset % NumChars + NumChars;
// ^ assures valid range, can still be negative
// ^ assures positive value, possibly
// out of range, but will be fixed later
for(;*input; ++input, ++output)
{
int c = *input - 'a';
// distance from character a
c = (c + offset) % NumChars;
// ^ fixes too large offset
*output = 'a' + c;
}
// as now iterating *until* null character found we now *need*
// to add it (in contrast to original version with whole array!)
*output = 0;
}
This variant includes an interesting idea: Let the caller define the offset to be applied! The modulo operation assures the valid range of the character, no matter how large the offset is. The great thing about: If a user encoded with some number n, exactly the same function can be used to decode again with -n (which is why I simply named it caesar according to the algorithm it implements). Note that this is untested code; if you find a bug please fix yourself...
Be aware, though, that this code still has two weaknesses:
It assumes ASCII encoding or compatible – at least one where letters a to z are in contiguous range, a is first character, z is last one. This is not true for all encodings, though, consider the (in-?)famous EBCDIC.
It assumes all input is in range of Latin minuscules only (from a - z), it does not consider white-space, digits, capital letters, punctuation marks... You might want to include special handling for all of these or at least the ones you might use.
You could fix these e.g. (many other variants are thinkable as well) by
converting all characters to either upper or lower case (toupper((unsigned char)*input) – assuming case doesn't matter)
search in an array of valid characters ("ABC...XYZ012...89") for the appropriate index and if found encode like above with NumChars being array length, otherwise (whitespace, punctuation) just leave as is.
In any case, the function would then be called like:
char input[128]; // prefer powers of 2 for array lengths...
char en[sizeof(input)];
char de[sizeof(input)];
gets_s(input, sizeof(input));
caesar(input, en, 7);
// en contains encrypted string, could e.g. be printed now
caesar(en, de, -7);
// de contains decrypted string
// you could even encode/decode in place:
caesar(input, input, 7);
// just be aware that this will fail, though, for the case if input
// and output overlap and input starts before output, as then at
// some point already encoded values will be read as input again:
// caesar(input, input + 1, 7) fails!!!
There's some issues in your code :
Not a very big issue for a beginner , but you should avoid gets function.
Because it doesn't check the input , it can cause buffers overflow and various security problems , try using fgets instead.
In encrypt , and decrypt functions , you are returning the address of an array located in the stack of the function , look :
const char *encrypt(char *str){
char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
Here , Since the en array is declared inside the function , after the return you may get garbage string when trying to read it.
The solution here , is to either malloc it , or declare a static array outside the function , and initialize it.
You are encrypting by adding 1 to the value of the string , and decrypt it by retrieving 3 . I don't know if this is what you intended to do.
Here's a new version of your code , try to check if it suits your need :
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
static char de[100] , en[100] ;
const char *decrypt(char *str1){
memset(de , 0 , 100) ;
int i=0;
for(;i<strlen(str1);i++){
de[i]=str1[i]-1;
}
de[i]='\0';
return (const char*) de;
}
const char* encrypt(char* str){
memset(en , 0 , 100) ;
int i=0;
for(;i<strlen(str);i++){
en[i]=str[i]+1;
}
en[i]='\0';
return (const char*) en;
}
int main(){
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
Your code does not handle a special case for the character 'z'. Thus
en[i]=str[i]+1;
Causes the character '{' to be written to the array en instead. For learning more about why this happens, I recommend you look at ASCII tables and looking at the integer values for alphabets.
Secondly, did you mean to type -3 in there?
de[i]=str1[i]-3;
This won't work if you're planning on using the decrypt() function to decrypt strings that you made using encrypt() because you're adding 1 to the character while encrypting and then subtracting a different number when decrypting, so the result will appear garbled.
I rewrote your code for you, since this is a beginner program, I made as little changes as possible so you can understand it. I WOULD HIGHLY RECOMMEND NOT USING gets() though... See here.
#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
encrypt(str);
printf("%s after encryption is %s\n", str, encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
decrypt(str1);
printf("%s after decryption is %s", str1, decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'z')
{
en[i] = 'a';
continue;
}
en[i] = str[i] + 1;
}
en[i] = '\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'a')
{
en[i] = 'z';
continue;
}
de[i] = str1[i] - 1;
}
de[i] = '\0';
return de;
}
Some criticisms
Like I said, gets() is really bad... See here for more details. Although it might be too complicated for you... A better alternative is fgets!
fgets(str, num, stdin)
takes user input from the console, and then stores it inside the array str, which must be large enough to store at least num characters. Don't worry about stdin if you don't know what that means. But be sure to always write it when using fgets as an alternative to gets
Like others have already posted, albeit using more technical jargon, it's a bad idea to declare an array inside a function and then return that array. You know the function ends when the return statement is hit, and at that point all the variables that were declared inside the function will get destroyed.
That doesn't necessarily mean that you can't read the data that was in them, but it becomes a probabilistic game where there's a teeny-tiny chance that the array will get corrupted after the function exits and before the data in that array is read. This is technically Undefined Behaviour.
I hope you know about pointers. You can modify the array which you passed as a parameter directly and then return that array, thus avoiding accessing an array outside it's lifetime.

Function that prints reverse of a string/char array in C

I am rather new to the C language right now and I am trying some practice on my own to help me understand how C works. The only other language I know proficiently is Java. Here is my code below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char * reverse(char word[]);
const char * reverse(char word[]) {
char reverse[sizeof(word)];
int i, j;
for (i = sizeof(word - 1); i <= 0; i--) {
for (j = 0; j > sizeof(word - 1); j++) {
reverse[i] = word[j];
}
}
return reverse;
}
int main() {
char word[100];
printf("Enter a word: ");
scanf("%s", word);
printf("%s backwards is %s\n", word, reverse(word));
return 0;
}
When the user enters a word, the program successfully prints it out when i store it but when i call the reverse function I made it doesnt return anything. It says on my editor the address of the memory stack is being returned instead and not the string of the array I am trying to create the reverse of in my function. Can anyone offer an explanation please :(
sizeof(word) is incorrect. When the word array is passed to a function, it is passed as a pointer to the first char, so you are taking the size of the pointer (presumably 4 or 8, on 32- or 64-bit machines). Confirm by printing out the size. You need to use strlen to get the length of a string.
There are other problems with the code. For instance, you shouldn't need a nested loop to reverse a string. And sizeof(word-1) is even worse than sizeof(word). And a loop that does i-- but compares i<=0 is doomed: i will just keep getting more negative.
There are multiple problems with your reverse function. C is very different from Java. It is a lot simpler and has less features.
Sizes of arrays and strings don't propagate through parameters like you think. Your sizeof will return wrong values.
reverse is an identifier that is used twice (as function name and local variable).
You cannot return variables that are allocated on stack, because this part of stack might be destroyed after the function call returns.
You don't need two nested loops to reverse a string and the logic is also wrong.
What you probably look for is the function strlen that is available in header string.h. It will tell you the length of a string. If you want to solve it your way, you will need to know how to allocate memory for a string (and how to free it).
If you want a function that reverses strings, you can operate directly on the parameter word. It is already allocated outside the reverse function, so it will not vanish.
If you just want to output the string backwards without really reversing it, you can also output char after char from the end of the string to start by iterating from strlen(word) - 1 to 0.
Edit: Changed my reverse() function to avoid pointer arithmetic and to allow reuse of word.
Don't return const values from a function; the return value cannot be assigned to, so const doesn't make sense. Caveat: due to differences between the C and C++ type system, you should return strings as const char * if you want the code to also compile as C++.
Arrays passed as params always "decay" to a pointer.
You can't return a function-local variable, unless you allocate it on the heap using malloc(). So we need to create it in main() and pass it as a param.
Since the args are pointers, with no size info, we need to tell the function the size of the array/string: sizeof won't work.
To be a valid C string, a pointer to or array of char must end with the string termination character \0.
Must put maximum length in scanf format specifier (%99s instead of plain %s — leave one space for the string termination character \0), otherwise vulnerable to buffer overflow.
#include <stdio.h> // size_t, scanf(), printf()
#include <string.h> // strlen()
// 1. // 2. // 3. // 4.
char *reverse(char *word, char *reversed_word, size_t size);
char *reverse(char *word, char *reversed_word, size_t size)
{
size_t index = 0;
reversed_word[size] = '\0'; // 5.
while (size-- > index) {
const char temp = word[index];
reversed_word[index++] = word[size];
reversed_word[size] = temp;
}
return reversed_word;
}
int main() {
char word[100];
size_t size = 0;
printf("Enter a word: ");
scanf("%99s", word); // 6.
size = strlen(word);
printf("%s backwards is %s\n", word, reverse(word, word, size));
return 0;
}

Recursion with C

I have the code below to reverse a string recursively, it works when I print the chars after the recursion is finished, but I can not figure out how to assemble the reverse chars into a string and return them reversed to the caller. Anyone have an idea? I don't want to add another parameter to accumulate chars, just this way, this is not homework, I am brushing up on small things since I will be graduating in a year and need to do well on interviews.
char* reversestring5(char* s)
{
int i = 0;
//Not at null terminator
if(*s!=0)
{
//advance the pointer
reversestring5(s+1);
printf("%c\n",*s);
}
}
With a recursive function, it's usually easiest to first figure out how to solve a trivial case (e.g. reversing a string with just a pair of characters) and then see how one might divide up the the problem into simple operations culminating with the trivial case. For example one might do this:
This is the actual recursive function:
char *revrecurse(char *front, char *back)
{
if (front < back) {
char temp = *front;
*front = *back;
*back = temp;
revrecurse(front+1, back-1);
}
return front;
}
This part just uses the recursive function:
char *reverse(char *str)
{
return revrecurse(str, &str[strlen(str)-1]);
}
Note that this assumes that the pointer is valid and that it points to a NUL-terminated string.
If you're going to actually reverse the characters, you can either provide a pair of pointers and recursively swap letters (which is what this routine does) or copy the characters one at a time into yet another space. That's essentially what your original code is doing; copying each character at a time to stdout which is a global structure that is not explicitly passed but is being used by your routine. The analog to that approach, but using pointers might look like this:
#define MAXSTRINGLEN 200
char revbuf[MAXSTRINGLEN];
char *refptr = revbuf;
char *revstring(char *s)
{
if (*s != 0)
{
revstring(s+1);
*refptr++ = *s; /* copy non-NUL characters */
} else {
*refptr++ = '\0'; /* copy NUL character */
}
return revbuf;
}
In this minor modification to your original code, you can now see the reliance of this approach on global variables revbuf and refptr which were hidden inside stdout in your original code. Obviously this is not even close to optimized -- it's intended solely for explanatory purposes.
"Reversing a string recursively" is a very vague statement of a problem, which allows for many completely different solutions.
Note that a "reasonable" solution should avoid making excessive passes over the string. Any solution that begins with strlen is not really a reasonable one. It is recursive for the sake of being recursive and nothing more. If one resorts to making an additional pass over the string, one no longer really needs a recursive solution at all. In other words, any solution that begins with strlen is not really satisfactory.
So, let's look for a more sensible single-pass recursive solution. And you almost got it already.
Your code already taught you that the reverse sequence of characters is obtained on the backtracking phase of recursion. That's exactly where you placed your printf. So, the "straightforward" approach would be to take these reversed characters, and instead of printf-ing them just write them back into the original string starting from the beginning of the string. A naive attempt to do this might look as follows
void reversestring_impl(char* s, char **dst)
{
if (*s != '\0')
{
reversestring_impl(s + 1, dst);
*(*dst)++ = *s;
}
}
void reversestring5(char* s)
{
char *dst = s;
reversestring_impl(s, &dst);
}
Note that this implementation uses an additional parameter dst, which carries the destination location for writing the next output character. That destination location remains unchanged on the forward pass of the recursion, and gets incremented as we write output characters on the backtracking pass of the recursion.
However, the above code will not work properly, since we are working "in place", i.e. using the same string as input and output at the same time. The beginning of the string will get overwritten prematurely. This will destroy character information that will be needed on later backtracking steps. In order to work around this issue each nested level of recursion should save its current character locally before the recursive call and use the saved copy after the recursive call
void reversestring_impl(char* s, char **dst)
{
if (*s != '\0')
{
char c = *s;
reversestring_impl(s + 1, dst);
*(*dst)++ = c;
}
}
void reversestring5(char* s)
{
char *dst = s;
reversestring_impl(s, &dst);
}
int main()
{
char str[] = "123456789";
reversestring5(str);
printf("%s\n", str);
}
The above works as intended.
If you really can't use a helper function and you really can't modify the interface to the function and you really must use recursion, you could do this, horrible though it is:
char *str_reverse(char *str)
{
size_t len = strlen(str);
if (len > 1)
{
char c0 = str[0];
char c1 = str[len-1];
str[len-1] = '\0';
(void)str_reverse(str+1);
str[0] = c1;
str[len-1] = c0;
}
return str;
}
This captures the first and last characters in the string (you could survive without capturing the first), then shortens the string, calls the function on the shortened string, then reinstates the swapped first and last characters. The return value is really of no help; I only kept it to keep the interface unchanged. This is clearest when the recursive call ignores the return value.
Note that this is gruesome for performance because it evaluates strlen() (N/2) times, rather than just once. Given a gigabyte string to reverse, that matters.
I can't think of a good way to write the code without using strlen() or its equivalent. To reverse the string in situ, you have to know where the end is somehow. Since the interface you stipulate does not include the information on where the end is, you have to find the end in the function, somehow. I don't regard strchr(str, '\0') as significantly different from strlen(str), for instance.
If you change the interface to:
void mem_reverse_in_situ(char *start, char *end)
{
if (start < end)
{
char c0 = *start;
*start = *end;
*end = c0;
mem_reverse_in_situ(start+1, end-1);
}
}
Then the reversal code avoids all issues of string length (or memory length) — requiring the calling code to deal with it. The function simply swaps the ends and calls itself on the middle segment. You'd not write this as a recursive function, though; you'd use an iterative solution:
void mem_reverse_in_situ(char *start, char *end)
{
while (start < end)
{
char c0 = *start;
*start++ = *end;
*end-- = c0;
}
}
char* reversestring5(char* s){
size_t len = strlen(s);
char last[2] = {*s};
return (len > 1) ? strcat(memmove(s, reversestring5(s+1), len), last) : s;
}
This is a good question, and the answer involves a technique that apparently few people are familiar with, judging by the other answers. This does the job ... it recursively converts the string into a linked list (kept on the stack, so it's quite efficient) that represents the reversal of the string. It then converts the linked list back into a string (which it does iteratively, but the problem statement doesn't say it can't). There's a complaint in the comments that this is "overkill", but any recursive solution will be overkill ... recursion is simply not a good way to process an array in reverse. But note that there is a whole set of problems that this approach can be applied to where one generates values on the fly rather than having them already available in an array, and then they are to be processed in reverse. Since the OP is interested in developing or brushing up on skills, this answer provides extra value ... and because this technique of creating a linked list on the stack and then consuming the linked list in the termination condition (as it must be, before the memory of the linked list goes out of scope) is apparently not well known. An example is backtrack algorithms such as for the Eight Queens problem.
In response to complaints that this isn't "pure recursive" because of the iterative copy of the list to the string buffer, I've updated it to do it both ways:
#include <stdio.h>
#include <stdlib.h>
typedef struct Cnode Cnode;
struct Cnode
{
char c;
const Cnode* next;
};
static void list_to_string(char* s, const Cnode* np)
{
#ifdef ALL_RECURSIVE
if (np)
{
*s = np->c;
list_to_string(s+1, np->next);
}
else
*s = '\0';
#else
for (; np; np = np->next)
*s++ = np->c;
*s = '\0';
#endif
}
static char* reverse_string_recursive(const char* s, size_t len, const Cnode* np)
{
if (*s)
{
Cnode cn = { *s, np };
return reverse_string_recursive(s+1, len+1, &cn);
}
char* rs = malloc(len+1);
if (rs)
list_to_string(rs, np);
return rs;
}
char* reverse_string(const char* s)
{
return reverse_string_recursive(s, 0, NULL);
}
int main (int argc, char** argv)
{
if (argc > 1)
{
const char* rs = reverse_string(argv[1]);
printf("%s\n", rs? rs : "[malloc failed in reverse_string]");
}
return 0;
}
Here's a "there and back again" [Note 1] in-place reverse which:
doesn't use strlen() and doesn't need to know how long the string is in advance; and
has a maximum recursion depth of half of the string length.
It also never backs up an iterator, so if it were written in C++, it could use a forward iterator. However, that feature is less interesting because it keeps iterators on the stack and requires that you can consistently iterate forward from an iterator, so it can't use input iterators. Still, it does mean that it can be used to in-place reverse values in a singly-linked list, which is possibly slightly interesting.
static void swap(char* lo, char* hi) {
char tmp = *hi;
*hi = *lo;
*lo = tmp;
}
static char* step(char* tortoise, char* hare) {
if (hare[0]) return tortoise;
if (hare[1]) return tortoise + 1;
hare = step(tortoise + 1, hare + 2);
swap(tortoise, hare);
return hare + 1;
}
void reverse_in_place(char* str) { step(str, str); }
Note 1: The "there and back again" pattern comes from a paper by Olivier Danvy and Mayer Goldberg, which makes for fun reading. The paper still seems to be online at ftp://ftp.daimi.au.dk/pub/BRICS/pub/RS/05/3/BRICS-RS-05-3.pdf

How to determine the length of a string (without using strlen())

size_t stringlength(const char *s)
Using this function, how could find the length of a string? I am not referring to using strlen(), but creating it. Any help is greatly appreciated.
Cycle/iterate through the string, keeping a count. When you hit \0, you have reached the end of your string.
The basic concepts involved are a loop, a conditional (to test for the end of string), maintaining a counter and accessing elements in a sequence of characters.
Note: There are more idiomatic/clever solution. However OP is clearly new to C and programming (no offense intended, we all started out as newbies), so to inflict pointer arithmetic on them as one of solutions did or write perhaps overly terse/compact solutions is less about OP's needs and more about a demonstration of the posters' programming skills :) Intentionally providing suggestions for a simple-to-understand solution earned me at least one downvote (yes, this for "imaginary code" that I didn't even provide. I didn't want to ready-serve a code solution, but let OP figure it out with some guidance).
Main Point: I think answers should always be adjusted to the level the questioner.
size_t stringlength(const char *s) {
size_t count = 0;
while (*(s++) != '\0') count++;
return count;
}
The confusing part could be the expression *(s++), here you're moving the pointer to point the next character in the buffer using the ++ operator, then you're using the dereferencing operator * to get the content at the pointer position. Another more legible approach would be:
size_t stringlength(const char *s) {
size_t count = 0;
while (s[count] != '\0') count++;
return count;
}
Another couple of reference versions (but less legible) are:
size_t stringlength(const char *s) {
size_t count = 0;
while (*s++) count++;
return count;
}
size_t stringlength(const char *s) {
const char* c = s;
for (; *c; c++);
return c - s;
}
Although the code stated here is just a reference to give you ideas of how to implement the algorithm described in the above answer, there exists more efficient ways of doing the same requirement (check the glibc implementation for example, that checks 4 bytes at a time)
This might not be a relevant code, But I think it worth to know.
Since it saves time...
int a[] = {1,2,3,4,5,6};
unsigned int i,j;
i = &a; //returns first address of the array say 100
j = &a+1; //returns last address of the array say 124
int size = (j-i)/sizeof(int); // (j-i) would be 24 and (24/4) would be 6
//assuming integer is of 4 bytes
printf("Size of int array a is :%d\n",size);
And for strings ::
char a[] = "Hello";
unsigned int i,j;
j = &a+1; //returns last address of the array say 106
i = &a; //returns first address of the array say 100
printf("size of string a is : %d\n",(j-i)-1); // (j-i) would be 6
If you are confused how come &a+1 returns the last address of the array, check this link.
Assuming s is a non-null pointer, the following function traverses s from its beginning until the terminating zero is found. For each character passed s++; count is incremented count++;.
size_t stringlength(const char *s) {
size_t count = 0;
while (*s) {
s++;
count++;
}
return count;
}

Resources