Recursive call that confuses me - c

I have the following function
int vowels(char *str)
{
int count = 0;
if (! str[0])
return count;
if (strchr("aeiouAEIOU", str[0]))
count ++;
return count + vowels(&str[1]);
}
That performs counting all the vowels that appear in a string, what confuses me is the recursive call vowels(&str[1]) do not understand why on every call goes to the next character, without doing this str++. They can help me understand this? please.

Within each function call that is declared like
int vowels(char *str);
though I would declare it like
size_t vowels( const char *str );
expression
&str[1]
is equivalent to
str + 1
or
++str
However you may not use
str++
because the value of the expression is the address stored in str before the increment.
As for me I would define the function the following way
size_t vowels( const char *s )
{
return *s ? ( strchr( "aeiouAEIOU", *s ) != NULL ) + vowels( s + 1 ) : 0;
}

vowels(&str[1]) calls vowels using the address 1 byte after &str[0], the start of str in memory. Because str is a char *, this means it uses the string minus its first character.
Note that you would not want to do str++ or &str++, as those would attempt to modify str itself, rather than just using part of the string.

There's is no reason to do str++ if the address to the next element is taken with &str[1].

Well strings are stored in memory. What this is doing is passing the address of a char to the char pointer of the function str. So &str[1] is simply the address of the next char of the array (it just jumps to the next byte).

Related

explanation of the souce code of strcat()

char *
STRCAT(char *dest, const char *src)
{
strcpy(dest + strlen(dest), src);
return dest;
}
what's the meaning of the code :dest + strlen(dest)?
and when I use the code like below:
#include <stdio.h>
#include <string.h>
void main()
{
char s[10]= "123456789";
char str[10] = " 123456789";
strcat(s,str);
printf("%s\n",s);
printf("%d",sizeof(s));
}
why the string s didn't overflow and the sizeof(s) did not change?
what's the meaning of the code :dest + strlen(dest)
It calculates the pointer to the end of the dest because with strcat you want to append the second string to the end of the first. It similar to:
size_t l = strlen(dest);
char *p = &dest[l]; // dest + l pointer arithmetic.
strcpy(p, src);
why the string s didn't overflow and the sizeof(s) did not change?
s is overflowing, because after strcat is done, your string is now 20 characters long, while it holds only room for 10 characters. This invokes undefined behavior.
sizeof doesn't change, because it is determined at compile time, so it will always show the same value.
strcat and STRCAT are two different functions.:)
I think you mean the function name strcat instead of STRCAT in this declaration
char *
strcat(char *dest, const char *src)
{
strcpy(dest + strlen(dest), src);
return dest;
}
This function is designed to deal with strings that is with sequences of characters terminated by the zero character '\0'.
The function strlen returns the number of characters in a string before the terminating zero character '\0';.
So the expression dest + strlen(dest) points to the terminating zero character '\0' of the string contained in the destination character array. Thus the function strcat can append the source string to the string stored in the destination array starting from the terminating zero.
So for example if you have a character array declared like
char dest[3] = { '1', '0' };
and the source array declared like
char src[2] = { '2', '0' };
For the array dest the function strlen( dest ) will return the value 1.
As a result dest + strlen( dest ) points to the second character of the array dest that is the zero character '0'. And this call
strcpy(dest + strlen(dest), src);
will copy characters of the string stored in the array src in the array dest starting with this position and you will get the following content of the array dest
{ '1', '2', '\0' }
In your program the expression sizeof( s ) gives the number of elements with which the array s is declared
char s[10]= "123456789"
that is 10. This value specified in the declaration of the array does not depend on the content that the array will have and is calculated at the compile time.
Pay attention to that values returned by the operator sizeof have the type size_t. So to output them using the function printf you have to use the conversion specifier zu. For example
printf("%zu\n",sizeof(s));
In your program the array str
char str[10] = " 123456789";
does not contain a string because it does not have a space to accommodate the (eleventh ) terminating zero character of the string literal used as an initializer.
On the other hand, the array s does not have a space to be able to append another string to its tail.
So your program has undefined behavior.
A valid program can look like
#include <stdio.h>
#include <string.h>
int main( void )
{
char str[] = " 123456789";
char s[10 + sizeof( str ) - 1] = "123456789";
strcat( s, str );
printf( "%s\n", s);
printf( "%zu\n", strlen( s ) );
printf( "%zu\n", sizeof( s ) );
}
Pay attention to that according to the C Standard the function main without parameters shall be declared like
int main( void )

Can you explain what while(*++str1) and return (str1 - str2) does?

In this context, does the while loop work like a for loop? Also, what does the str1-str2 string subtraction result in?
#include <stdio.h>
int fun(char *str1) {
char *str2 = str1;
while (*++str1);
return (str1 - str2);
}
int main() {
char *str = "GeeksQuiz";
printf("%d", fun(str));
return 0;
}
Notice that you are working here with pointers and not strings, so starting from the end, str1-str2 is a pointers arithmetic.
As you know string should be ended with a null, so in the memory "GeeksQuiz" is actually an array of chars that has the next values: GeeksQuiz\0. In that way, while(*++str1); will run through the values of this array till it reaches \0.
To conclude, this function will return the number of chars in the string.
The purpose of the function is to calculate the length of a string. That is this while loop
while(*++str1);
iterates until the terminating zero character '\0' is encountered. It is supposed that after the while loop the pointer str1 will point to the terminating zero character '\0' while the pointer str2 will point to the beginning of the string due to the initial assignment
char *str2 = str1;
So the difference str1-str2 will yield the length of the string. The length of a string is determinate as the number of characters in the string before the terminating zero character '\0'.
However the function has a bug. If the user will pass an empty string "" that is internally represented as a character array with one element that is equal to the terminating zero character { '\0' } then the function invokes undefined behavior. So an empty string contains in its first character the terminating zero character '\0'. However in the while loop the pointer str1 at first incremented and then already the next character is checked whether it is the terminating zero character '\0'.
That is this while loop
while(*++str1);
may be rewritten the following way
while ( ( ++str1, *str1 != '\0' ) );
As it is seen at first the pointer str1 is incremented.
Apart from this defect the function parameter should have the qualifier const because within the function the passed string is not being changed. Also the return type of the function should be unsigned integer type as for example size_t (it is the return type of the standard C string function strlen that does the same task.)
The function can be declared an define the following way
size_t fun( const char *s )
{
const char *t = s;
while( *t ) ++t;
return t - s;
}
Here is a demonstrative program.
#include <stdio.h>
size_t fun( const char *s )
{
const char *t = s;
while( *t ) ++t;
return t - s;
}
int main(void)
{
const char *s = "";
printf( "The length of the string \"%s\" is equal to %zu\n", s, fun( s ) );
s = "1";
printf( "The length of the string \"%s\" is equal to %zu\n", s, fun( s ) );
s = "12";
printf( "The length of the string \"%s\" is equal to %zu\n", s, fun( s ) );
s = "123";
printf( "The length of the string \"%s\" is equal to %zu\n", s, fun( s ) );
return 0;
}
The program output is
The length of the string "" is equal to 0
The length of the string "1" is equal to 1
The length of the string "12" is equal to 2
The length of the string "123" is equal to 3
The loop while (*++str1); increments the pointer, reads the byte pointed to by the updated str1, and tests if this byte is null, if not it stops otherwise do nothing and repeat. This loop would be more readable with an explicit statement instead of an empty statement ;:
while (*++str1 != '\0')
continue;
return (str1 - str2); computes the difference of pointers str1 and str2 and returns this value as an int. The difference of 2 pointers is defined if they point to the same array and evaluates to the number of elements between them.
The function attempts to compute the length of the string argument but would fail for the empty string because str1 is always incremented before the test, hence would skip the null terminator at offset 0 for the empty string. The behavior is undefined as the code then reads beyond the end of the string. For non empty strings, It prints the number of non null characters, aka the length of the string: fun("GeeksQuiz") returns 9.
Here is a modified version:
#include <stdio.h>
int fun(const char *str) {
const char *start = str;
while (*str != '\0')
str++;
return str - start;
}
int main() {
const char *str = "GeeksQuiz";
printf("length of \"%s\" is %d\n", str, fun(str));
return 0;
}
I ran your code through clang-format [see Note 1] to confirm what I suspected about the weird while loop you've got going on there, and I came up with this as correct formatting for your code:
#include <stdio.h>
int fun(char *str1)
{
char *str2 = str1;
while (*++str1)
;
return (str1 - str2);
}
int main()
{
char *str = "GeeksQuiz";
printf("%d", fun(str));
return 0;
}
Personally, I would have written it like this though, to make the while loop super obvious. You can run this code here: https://onlinegdb.com/BkxlKb75GO.
#include <stdio.h>
int fun(char *str1)
{
char *str2 = str1;
while (*++str1)
{
// do nothing
}
return (str1 - str2);
}
int main()
{
char *str = "GeeksQuiz";
printf("%d", fun(str));
return 0;
}
Even more-readable, however, is this for the fun() function, which I've also renamed to count_num_chars_in_str():
int count_num_chars_in_str(char *str1)
{
char *str2 = str1;
while (*str1 != '\0')
{
str1++;
}
return str1 - str2;
}
A shorter name might be num_chars_in_str(), str_length(), or strlen(). strlen() already exists (see here and here), and this is precisely what it does. It can be included by header string.h, and is part of the C and C++ standard. Here's its description on cplusplus.com:
size_t strlen ( const char * str );
Get string length
Returns the length of the C string str.
The length of a C string is determined by the terminating null-character: A C string is as long as the number of characters between the beginning of the string and the terminating null character (without including the terminating null character itself).
This should not be confused with the size of the array that holds the string.
So, running any of these programs above, the output is 9. All the program does is count the number of non-null chars (where a null char is 0, or '\0'--same thing) in the string passed in, which is GeeksQuiz in this case. GeeksQuiz contains 9 non-null chars.
Where did you get your code by the way? Please post links and references. You should always reference your sources.
while (*++str) simply keeps incrementing the str pointer one char at a time until a null terminator (0) is found, which occurs right at the end of the string, after the last char in it. Once that happens, the difference between the two char pointers is taken, resulting in the difference between the address location of the null terminator right after the z, and the address location of the first char in the string, which is G. The difference in memory address between these 2 chars is 9 chars.
Not only is the original version less-readable, it also has a bug in it. For this test case, it should print 0, but it prints 1 instead:
char *str = "\0";
printf("%d", fun(str));
My more-readable version in count_num_chars_in_str() corrects this bug too.
Lesson: don't write unreadable or obfuscated code.
[Note 1] The way I ran it through clang-format is I just copy-pasted your original code into a main.c file, then copied that into my eRCaGuy_CodeFormatter repo here, then ran ./run_clang-format.sh.
In this context, does the while loop work like a for loop?
I would say that all while loops act like for loops, and vice versa.
Any time you have a loop
while(condition)
{ /* do something */; }
you can replace it by an equivalent for loop:
for(; condition; )
{ /* do something */; }
Going the other way, any time you have a for loop
for(initial_expression; test_expression; increment_expression)
{ /* do something */; }
you can (almost) replace it with an equivalent while loop:
initial_expression;
while(test_expression) {
/* do something */;
increment_expression;
}
(There's one small difference between the two, but it only shows up if you use a continue statement in the loop.)
If you were stranded on a desert island with a broken C compiler (or if you were stranded in the classroom of an instructor who likes to pose "trick" questions), and you had to write a C program without using the for keyword, you could: you could write all your loops using while instead, without loss of functionality.

Assigning char to char* using pointers

Let's say I have a char *str and I want to assign it characters one by time using using pointers and incrementing ?
I've done :
char *str;
char c = 'a';
*str++ = c;
But it doesn't work.
How can I do that ?
str is just a pointer. It doesn't point anywhere valid (especially not to some memory you could write to). A simple possibility would be to have it point to an array:
char buf[1024] = {0}; // room for 1024 chars (or 1023 + a 0 byte for a string)
char *str = buf;
char c = 'a';
*str++ = c;
char *str is a pointer to a char (or an array of chars), however, you never assigned it. As has been mentioned earlier a char * basically says "go there" but there is no there there, you never gave it a value. You first need to use malloc to create space to put things in. Here's an example
char *str = malloc(sizeof(char)*10) //allocate space for 10 chars
char c = 'a';
str[0] = c;
no error check was made to malloc which you should do in your own program. You can also do it as such
char str[10];
char c = 'a';
str[0] = c;
however with this method you will be restricted to 10 chars and you cannot change that amount, with the previous method you can use realloc to get more or less space in your array.
But it doesn't work.
char* str;
... is not initialized to anything, therefore dereferencing it is to undefined behaviour. If it where initialized, then in expression *str++ = c; str++ is a post-increment operator, which returns a copy of the pointer whilst incrementing the original. The effect is that the copy points to the previous, and therefore what is pointed to by the previous pointer is assigned c.
To which part that doesn't work are you referring?
EDIT:
As mentioned in one of the comments, a copy is not really returned but the value is increment in place after having been evaluated.
As a variable with automatic storage duration the pointer str has indeterminate value. If even it had the static storage duration its value would be NULL. So you may not use such a pointer to store data.
What you mean can look for example the following way
#include <stdio.h>
int main( void )
{
char s[11];
char *p = s;
while (p != s + sizeof( s ) / sizeof( *s ) - 1 ) *p++ = 'a';
*p = '\0';
puts(s);
return 0;
}
The program output is
aaaaaaaaaa
Here in the program the pointer p of the type char * is initialized by the address of the first character of the array s.
Thus this statement used in the loop
*p++ = 'a';
fills sequentially the array with the character 'a'.
The next example is more interesting
#include <stdio.h>
char * copy_string(char *dsn, const char *src)
{
for (char *p = dsn; (*p++ = *src++) != '\0'; )
{
// empty body
}
return dsn;
}
int main( void )
{
char *src = "Hi QBl";
char dsn[7];
puts(copy_string(dsn, src));
return 0;
}
The program output is
Hi QBl
Here is a demonstration of a function that copies one character array containing a string into another character array using pointers.

Pointers of strings in C

In the case down below.
Does changing the string 'out' change the string 'str' respectively? In other words, do they have the same pointer?
Thank you in advance.
int main() {
char str[]={'g','o','o','d','/0'};
char special[]={'o','/0'};
char* out=str;
return 0;
}
It depends. If you write:
out = "hello!";
you do not change the string str, but simply make out point to another memory location.
But if you write into out like in this:
sprintf(out, "abcd");
then you do change str. But beware of overflow!
For starters I think you mean the terminating zero '\0' instead of the multibyte character literal '/0'.
To escape such an error it is better to initialize character arrays with string literals (if you are going to store a string in an array). For example
char str[] = { "good" };
or just like
char str[] = "good";
As for the question then after this assignment
char* out=str;
the pointer out points to the first character of the array str. Thus using this pointer and the pointer arithmetic you can change the array. For example
char str[] = "good";
char *out = str;
out[0] = 'G';
*( out + 3 ) = 'D';
puts( str );
Moreover an array passed as an argument to a function is implicitly converted to pointer to its first character. So you can use interchangeably either an array itself as an argument or a pointer that initialized by the array designator. For example
#include <stdio.h>
#include <string.h>
//...
char str[] = "good";
char *out = str;
size_t n1 = strlen( str );
size_t n2 = strlen( out );
printf( "n1 == n2 is %s\n", n1 == n2 ? "true" : "false" );
The output of this code snippet is true.
However there is one important difference. The size of the array is the number of bytes allocated to all its elements while the size of the pointer usually either equal to 4 or 8 based on used system and does not depend on the number of elements in the array. That is
sizeof( str ) is equal to 5
sizeof( out ) is equal to 4 or 8
Take into account that according to the C Standard the function main without parameters shall be declared like
int main( void )
I think there's a typo in your code, you have written '/0' but it's not a null character but '\0' is.
As far as out & str are concerned, str[] is a char array, whereas out is a pointer to it. If you make out point to some other char array there'll be no effect on str. But you can use out pointer to change the values inside the str[], like this,
int main( void )
{
char str[]={'g','o','o','d','\0'}; // There was a typo, you wrote '/0', I guess you meant '\0'
//char special[]={'o','\0'};
char* out=str;
for(int i=0; out[i] != '\0'; i++)
{
out[i] = 'a';
// This will write 'a' to the str[]
}
printf("out: %s\n", out);
printf("str: %s", str);
return 0;
}
No. out is a different variable that holds the same address str is at, i.e. it points to the same location. Note that changing *str will change *out.
In C, assignment takes the value of the right end and stores it in the left end, it does not makes the right "become" left

Return pointer to a subarray

Let's say I have function that has a char array as its parameter and char* as its return type. I want to return a pointer to the subarray of the parameter array.
For example : char str[] = "hi billy bob";
I want my function to return "billy bob";
Let's say in the body of my function I was able to get the index
of where I want the subarray to start.
char* fun(const char s1[]) {
int index = a random int;
/* char *p = *(s1[index1]); */
return p;
}
I'm having trouble with the commented out line.
Simply use
const char *p = &str[index]; /* may also write p = str + index */
return p;
The above takes the address of the character at index index -- which is a pointer to char array beginning at this index. The string continues until the first '\0' character which is the end of the original str.
In your case, if you want the output to be "billy bob" (Note that you cannot change the capitalization unless you modify the string or return a new one) you should set index = 3;.
It gets more involved when you want to take a substring of str. Then you either have to set str[end_index]='\0' or use malloc to allocate a new array and copy the relevant part.
Some information regarding the two syntax options
In C, the expression a[i] is equivalent to *(a+i). I.e., take the pointer a, move it forward i elements (chars in your case) and then return the element at the resulting address.
If you prefix a[i] with an & operator to get the address of that character. So &a[i] may be written as &*(a+i). The operators '&' and '*' cancel each other and you are left with a+i.
What you want is this
char *random_sub_string(const char *string)
{
size_t length;
if (string == NULL)
return NULL;
length = strlen(string);
return string + rand() % length;
}
char *fun(const char str[])
{
int index = x; /* where `x' is some non-negative value less than the
length of the input string */
return str + index;
}
This is the cleanest way of returning the string you're looking to return. The main idea here is that, in C, a string is defined as a null-terminated array of characters. Null-terminated means the array contains the \0 character, and the location of the \0 denotes the end of the string. Moreover, a char[] and char * are both pointers to a char. Thus, they can be accessed in the same way. In the return statement above, we make use of pointer arithmetic to compute a pointer to a substring of the input string. If you're not familiar with pointer arithmetic, it would be a good idea to read up on it.

Resources