Let's break it down, albeit my C skills are somewhat rusty. Edits are welcome :)
void *ft_memset(void *b, int c, size_t len)
{
size_t i;
i = 0;
while (i < len)
{
((unsigned char *)b)[i] = c;
i++;
}
return (b);
}
First, you have declared a function called ft_memset which returns void *.
void * means a pointer to any object. It's just a number, pointing to a memory address. But we do not know what's in it because it's not properly annotated.
Your function takes three arguments:
b which is a pointer to anything (or void pointer if you will)
c which is an int 32-bit signed integer number.
len which is a size_t which is usually an alias to an unsigned integer. Read more about size_t over here
Your function iterates through the first len bytes and sets the c's value to those.
We're basically overwriting b's contents for the first len bytes.
Now, what does ((unsigned char*)b) mean. This statement is casting your void * to an unsigned char* (byte pointer), this is just
telling the compiler that we're gonna deal with the contents pointed by b as if they were just a unsigned char.
Later we're just indexing on the i-th position and setting the value c in it.
Calculating length of a string with strlen()
Understanding code of function strlen in C Programming - Stack Overflow
string - strlen function in c - Stack Overflow
arrays - How does strlen function works in c? - Stack Overflow
Videos
Let's say that we have a string char myStr[] = "Hello there!"
The 1st option to calculate the length is
int length = sizeof(myStr)/ sizeof(myStr[0]);
The 2nd option is simply to use the strlen() function, but I'm seeing that it will not count the null terminating character at the end.
My question: Would it be a problem using strlen() in embedded projects since it dosn't include the null terminating character as it's length? Or it's safer to just use the 1st option instead?
I'm thinking as an example of a case when you need to allocate emory, and you're relying on this strlen() function, it will not allocate for the null character, which might lead to problems down the line?
Thanks
Let's break it down, albeit my C skills are somewhat rusty. Edits are welcome :)
void *ft_memset(void *b, int c, size_t len)
{
size_t i;
i = 0;
while (i < len)
{
((unsigned char *)b)[i] = c;
i++;
}
return (b);
}
First, you have declared a function called ft_memset which returns void *.
void * means a pointer to any object. It's just a number, pointing to a memory address. But we do not know what's in it because it's not properly annotated.
Your function takes three arguments:
b which is a pointer to anything (or void pointer if you will)
c which is an int 32-bit signed integer number.
len which is a size_t which is usually an alias to an unsigned integer. Read more about size_t over here
Your function iterates through the first len bytes and sets the c's value to those.
We're basically overwriting b's contents for the first len bytes.
Now, what does ((unsigned char*)b) mean. This statement is casting your void * to an unsigned char* (byte pointer), this is just
telling the compiler that we're gonna deal with the contents pointed by b as if they were just a unsigned char.
Later we're just indexing on the i-th position and setting the value c in it.
Understanding code of function strlen
void *ft_memset(void *b, int c, size_t len) is like void *memset(void *s, int c, size_t n). They both assign values to the memory pointed to by b. These functions are quite different form strlen().
size_t strlen(const char *s) does not alter the memory pointed to by s. It iterates through that memory looking for a null character.
size_t strlen(const char *s) {
const char *end = s;
while (*end != '\0') {
end++;
}
return (size_t)(end - s);
}
// or
size_t strlen(const char *s) {
size_t i = 0;
while (s[i] != '\0') {
i++;
}
return i;
}
There's a good chance that you're doing this to a string that you have obtained with fgets or a similar input function. In that case, it may well have the newline at the end still.
If you change your code temporarily to:
void xyz (char *number) {
int i = 0, length = strlen (number);
while (i < length)
printf ("Number[%d]: %c (%d)", i, number[i], number[i]);
i++;
}
}
that should also show the numeric codes for all characters.
The problem with encoding something like that - 2 in your function is that it will not work with:
xyz ("123");
since it will stop early, printing out only 12. The caller should be calling with valid data, meaning that it should adjust the value to be a numeric string before calling.
You can see this happening in the following program:
#include <stdio.h>
#include <string.h>
void xyz (char *number) {
int i = 0, length = strlen(number) - 2;
while(i <= length)
{
printf("Number[%d]: %c (%d)\n",i, number[i], number[i]);
i++;
}
puts ("===");
}
void xyz2 (char *number) {
int i = 0, length = strlen(number);
while(i < length)
{
printf("Number[%d]: %c (%d)\n",i, number[i], number[i]);
i++;
}
puts ("===");
}
int main (void) {
char buff[100];
printf ("Enter number: ");
fgets (buff, sizeof (buff), stdin);
xyz (buff);
xyz ("12345");
xyz2 (buff);
xyz2 ("12345");
return 0;
}
The (annoted) output of this, if you enter 98765, is:
Enter number: 98765
Number[0]: 9 (57)
Number[1]: 8 (56)
Number[2]: 7 (55) # Your adjustment works here because of the newline.
Number[3]: 6 (54)
Number[4]: 5 (53)
===
Number[0]: 1 (49)
Number[1]: 2 (50)
Number[2]: 3 (51) # But not here, since it skips last character.
Number[3]: 4 (52)
===
Number[0]: 9 (57)
Number[1]: 8 (56)
Number[2]: 7 (55) # Here you can see the newline (code 10).
Number[3]: 6 (54)
Number[4]: 5 (53)
Number[5]:
(10)
===
Number[0]: 1 (49)
Number[1]: 2 (50)
Number[2]: 3 (51) # And proper numeric strings work okay.
Number[3]: 4 (52)
Number[4]: 5 (53)
===
If you're looking for a robust user input function that gets around this problem (and avoids dangerous things like unbounded scanf("%s") and gets), I have one elsewhere on SO (right HERE, in fact) drawn from my arsenal.
Check if this works for you --
void xyz(char *number)
{
int length = strlen(number);
while(i < length)
{
printf("Number[]: %c",number[i]);
i++;
}
}
and this function, if invoked as
xyz("1234");
should print out:
Number[]: 1
Number[]: 2
Number[]: 3
Number[]: 4
Is that what you really wanted ? If so, then let me point 2 mistakes.
1) "i" is not initialized. It is more a question of good practise. Explicitly initialize your loop control variable (to zero in this case), just don't assume it to be set. 2) your while loop condition with "<=" runs 1 extra cycle that it should.
Remember that arrays start from index '0' (zero), and an array of size 10, has valid index from 0 to 9, and C lang uses null character ('\0'), to terminate a string. So, your "1234" is actually stored as:-
string[0] = '1' string[1] = '2' string[2] = '3' string[3] = '4' string[4] = '\0' (<= NULL)
so if your loop-counter (control variable) i=0 at beginning of loop, for first iteration, you pick string[0], and for 2nd iteration (when i=1) you pick string[1]... and this way, the loop should run only 4 times, i.e. when i==4 (i.e. loopcounter < string-length), you must stop & exit loop.
Hope this clears up your doubt and help. If so, please don't forget to accept the answer.
char test_string[5];
test_string is an array of 5 uninitialized char objects.
for (init = 0; init < strlen(test_string); init++)
Kaboom. strlen scans for the first '\0' null character. Since the contents of test_string are garbage, the behavior is undefined. It might return a small value if there happens to be a null character, or a large value or program crash if there don't happen to be any zero bytes in test_string.
Even if that weren't the case, evaluating strlen() in the header of a for loop is inefficient. Each strlen() call has to re-scan the entire string (assuming you've given it a valid string), so if your loop worked it would be O(N2).
If you want test_string to contain just zero bytes, you can initialize it that way:
char test_string[5] = "";
or, since you initialize the first 4 bytes later:
char test_string[5] = "TEST";
or just:
char test_string[] = "TEST";
(The latter lets the compiler figure out that it needs 5 bytes.)
Going back to your declarations:
char test_string2[] = { 'G', 'O', '_', 'T', 'E', 'S', 'T'};
This causes test_string2 to be 7 bytes long, without a trailing '\0' character. That means that passing test_string2 to any function that expects a pointer to a string will cause undefined behavior. You probably want something like:
char test_string2[] = "GO_TEST";
strlen searches for '\0' character to count them, in your test_string, there is none so it continues until it finds one which happens to be 6 bytes away from the start of your array since it is uninitialized.
The compiler does not generate code to initialize the array so you don't have to pay to run that code if you fill it later.
To initialize it to 0 and skip the loop, you can use
char test_string[5] = {0};
This way, all character will be initialized to 0 and your strlen will work after you filled the array with "TEST".
It doesn't use the preprocessor, but sizeof is resolved at compile time. If your string is in an array, you can use that to determine its length at compile time:
static const char string[] = "bob";
#define STRLEN(s) (sizeof(s)/sizeof(s[0]))
Keep in mind the fact that STRLEN above will include the null terminator, unlike strlen().
You can do:
#define MYSTRING sizeof("bob")
That says 4 on my machine, because of the null added to the end.
Of course this only works for a string constant.
Using MSVC 16 (cl.exe -Wall /TC file.c) this:
#include "stdio.h"
#define LEN_CONST(x) sizeof(x)
int main(void)
{
printf("Size: %d\n", LEN_CONST("Hej mannen"));
return 0;
}
outputs:
Size: 11
The size of the string plus the NUL character.
For starters you should not name your user-defined functions the same ways as standard C functions.
There is already standard C function with the name atoi declared in header <stdlib.h>. Using the same name can result in compiler or linker errors.
Your function atoi declared like
int atoi(const char *s[]){
that is the same as
int atoi(const char **s){
due to adjusting by the compiler a parameter having an array type to pointer to the array element type accepts a "double" pointer. So using the function strlen with the double pointer invokes undefined behavior
printf(" The length is %d",strlen(s));
The function strlen expects an argument of the type char * or const char * but not an argument of the type const char **.
Moreover the return value of the function strlen has the type size_t. And using the conversion specifier %d in a call of printf with a corresponding argument expression of the type size_t again invokes undefined behavior. You have to use the conversion specifier %zu instead of %d.
This for loop
for(int i = 0; i< length; ++i){
printf("This is %s",*(s+i));
}
does not make sense because the variable length actually does not contain the number of elements in the passed array.
You need either explicitly to pass the number of elements in the array or the array should have a sentinel value.
And the return type of the function int also does not make sense because the returned value 0 reports nothing useful to the caller of the function.
If the function is designed only to traverse a string in a for loop then it should be declared like for example
char * func( const char *s )
{
for ( const char *p = s; *p != '\0'; ++p )
{
putchar( *p );
}
return ( char * )s;
}
If you want to pass to the function an array of strings then the function can be implemented for example the following way as shown in the demonstration program below provided that the array contains a sentinel value
#include <stdio.h>
void func( const char **s )
{
for ( ; *s != NULL; ++s )
{
printf( "%s ", *s );
}
}
int main( void )
{
const char * s[] = { "Hello", "World!", NULL );
func( s );
putchar( '\n' );
}
The program output is
Hello World!
- Do not use standard function names
strlentakes a pointer tocharand returnssize_t(not int)- Your print format is wrong.
- Your function takes an array of pointers not a pointer to
char
int myfunc(const char *s)
{
size_t length = strlen(s);
printf(" The length is %zu", length);
for(size_t i = 0; i< length; ++i){
printf("This is '%c'\n",*(s+i));
}
return 0;
}
Why is there an empty while loop? The loop increments eos until it points to the location directly after the null terminator. The expression *eos++ is very compact way of telling your computer to get the char value eos is currently pointing to, and then increment eos so it points at the next char. There is no need for a body in this while loop.
Why does it use a local variable? Since we are incrementing a pointer (i.e. eos), and we also need a pointer to the beginning of the string in the final computation (i.e. str), we can't simply use str for everything. We need at least one other variable to get the job done.
How does the last line work? The expression eos - str does pointer subtraction, so it calculates the distance between those two pointers and returns that as an integer. Then we subtract 1 to make the answer correct.
The pointer eos is used to advance along the string. EOS is an abbreviation for end-of-string. The while loop is empty because is doesn't need to do anything - because advancing the pointer is all that is needed. Once eos points at the null terminator, the loop exits. The last line of the function then subtracts the end pointer from the start pointer, to give the number of characters that eos moved past. The last -1 is there to correct for the fact that, thanks to the post-increment operator, eos is always advanced one character more than it should be.
A less confusing implementation would have been:
int strlen(const char *str)
{
const char* eos = str; // 1
while (*eos)eos++; // 2
return (eos - str); // 3
}