here is the prototype:
void *memset(void *s, int c, size_t n)
first im not sure if I have to return something because when I use the memset i do for example
memset(str, 'a', 5);
instead of
str = memset(str, 'a', 5);
here is where I am with my code:
void *my_memset(void *b, int c, int len)
{
int i;
i = 0;
while(b && len > 0)
{
b = c;
b++;
len--;
}
return(b);
}
int main()
{
char *str;
str = strdup("hello");
my_memset(str, 'a', 5);
printf("%s\n", str);
}
I dont want to use array in this function, to better understand pointer and memory, so I dont get 2 things:
- how to copy the int c into a character on my void b pointer
- what condition to use on my while to be sure it stop before a '\0' char
edit: i was wondering is there a way to do this function without casting ?
how to copy the int c into a character on my void b pointer
You convert the void pointer to an unsigned char pointer:
void *my_memset(void *b, int c, int len)
{
int i;
unsigned char *p = b;
i = 0;
while(len > 0)
{
*p = c;
p++;
len--;
}
return(b);
}
what condition to use on my while to be sure it stop before a '\0' char
memset have to trust the length that is passed in. memset needs to work on a general piece of memory, not just a 0 terminated string - so there should not be such a check.
If you anyway would need to check for a 0 byte. you'd do
if (*p == 0) //or if(!*p )
break;
Pointer arithmetic is based on offsetting the pointer by the size of the type it points to. Before you start incrementing that pointer, you should transform it from void* to pointer to char / unsigned char:
void* my_memset(void *s, int c, size_t len) {
unsigned char *dst = s;
while (len > 0) {
*dst = (unsigned char) c;
dst++;
len--;
}
return s;
}
also note that memset returns a pointer to the memory area s, so you should return the original pointer (before you start incrementing it).
The reason functions often return a value is to return an error state to the calling function. In memory related functions it's usually the same pointer as where your result should be (including NULL). In your example you might not want to use the return value of your my_memset function, but usually it's because it can be included in a code evaluation (can't think of a better word for this), e.g.
if(!my_memset((void *)str, 'a', 5))
{
printf("An error occurred in my_memset()\n");
}
or in a macro, e.g. to return pointer to the end of the memory where you copied your char:
#define INIT_MEM_PTR_END(a,x) (my_memset((void *)&(a), (x), sizeof(a)) + sizeof(a))
This is probably not a great example (plus the potential issues if a is already a pointer, etc...), but it shows that you can reuse the result without having to write another couple of lines for this to evaluate the result and so on.
You should also check your pointers before dereferencing them. If for example void *b is NULL, you'll have a segmentation fault.
Nothing wrong with passing in void *, other than the fact that the intention of the function may not be as clear as when passing pointer to a particular data type. Make sure you cast it to something valid though inside. Also this way, the function can be used to set any memory to a particular hex value (through char) or all 0's quite easily.
It would seem like in this case b should be cast to the same type as the value you're trying to copy into it, an int; however, then the len argument becomes unclear, is it size in bytes or number of times c should be copied to the b pointer?
Since in your main() you're copying a char into that memory location, then it's just better to change your c to a char, cast your b to a char* and make len the length in bytes or number of times c should be copied to *b. Avoid ambiguity.
The way you have written it, it will copy c number of times specified by len or until you meet the null character, whichever is shortest/soonest. That's fine, if that's your intention.
void *my_memset(void *b, char c, int len)
{
char *b_char = (char *)b;
if (b == NULL) return NULL;
while(*b_char && len > 0)
{
*b_char = c;
b_char++;
len--;
}
return b; //as this pointer has not changed
}
int main()
{
char *str;
str = strdup("hello");
if (!my_memset((void *)str, 'a', 5))
{
printf("An error occurred in my_memset()\n");
}
else
{
printf("%s\n", str);
}
}
void *my_memset(void *b, int c, int len)
{
if (b == NULL || len <= 0)
return b;
unsigned char *ptr = b;
while(*ptr != '\0' && len--)
{
*ptr++ = (unsigned char)c;
}
return(b);
}
You could use a duff device to have even better performance.
#define DUFF_DEVICE_8(aCount, aAction) \
do { \
int count_ = (aCount); \
int times_ = (count_ + 7) >> 3; \
switch (count_ & 7){ \
case 0: do { aAction; \
case 7: aAction; \
case 6: aAction; \
case 5: aAction; \
case 4: aAction; \
case 3: aAction; \
case 2: aAction; \
case 1: aAction; \
} while (--times_ > 0); \
} \
} while (0)
I tried one implementation like this:
void memset(void *b, int c, int len)
{
char *s = b;
while(len--)
*s++ = c;
}
Related
I was given a solution to the problem of recreating the function strlen in C Programming and it was the following, I need help understanding what the code is actually doing.
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);
}
My biggest doubts are the meaning of ((unsigned char *)b)[i] = c, specially because I don't understand the ( *)b, and the need for a return b in a void function.
Thank you very much for your help, sorry if I did something wrong its my first post in stack overflow.
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;
}
I need to write a code for my UNI, in which I have to receive 2 arrays of some data (it may be int array or char array or even float array) and compare n characters from pointers in both of the arrays, so far I am stuck with this
*note in other words - I need to write my own memcmp :
int byte_compare(const void *b1,const void *b2,size_t len)
{
char *q1 = (char *)p1;
char *q2 = (char *)p2;
int i;
for (i=0; i<=len*sizeof(*q1) ;i++)
{
if(*q1++ != *q2++)
return 1;
}
return 0;
}
int main()
{
char str1[] = "abcheya";
char str2[] = "gtyheyb";
printf((byte_compare(str1[3],str2[3],3))?"not equal\n":"equal\n");
/*the output is equal*/
int arr1[]={1,2,3,4};
int arr2[]={1,2,7,59};
printf((byte_compare(arr1[0],arr2[0],3))?"not equal\n":"equal\n");
/*the output is also equal although it is not supposed to be*/
return 0;
}
when I compare strings it works just fine, but when I try to compare int or float it wont work properly, please help me.
You should calculate the comparing byte length while passing the len parameter. So, you can use templates for this.
template<typename T>
int byte_compare(const T *b1, const T *b2, size_t len)
{
return memcmp(b1, b2, len * sizeof(T));
}
Edit note : The question is edited and the answer has no more meaning. And it uses C++, not applicable for C lessons. I'm remaining the answer for whose have no restriction to use C++.
Edit: to write own memcmp function
int byte_compare(const void *b1,const void *b2,size_t len)
{
if (len != 0) {
register const unsigned char *p1 = b1, *p2 = b2;
do {
if (*p1++ != *p2++)
return (*--p1 - *--p2);
} while (--len != 0);
}
return (0);
}
You need to pass the size of the objects, not their length:
int byte_compare(const void *b1, const void *b2, size_t size)
{
return memcmp(b1, b2, size);
}
Your instructor probably does not want you to use a library call. So write a byte by byte comparison (aka memcmp).
Get a copy of K&R C (or another book on C), and you will find examples of how to process char(acter) values in a loop.
int byte_compare(const void *b1,const void *b2,size_t len)
{
if( !b1 || !b2 ) return 0; //0 represents false
char* p1=(char*)b1; char* p2=(char*)p2;
for( ; len --> 0; ) {
if( *p1++ != *p2++ ) return 0;
}
return 1;
}
I would like not just to know if the substring exists in a buffer, but to get the position it ends. I am doing a ftp and it will look for #filestart; to start copying the file and only will return the file when it finds #fileend;
I will send the first message with something like that: #filestart;len=50;
The first part is easy, cause I can use the strstr to find #filestart. But after that I would like to know the end of len, so I can "run" into the buffer, from that position forward until find the equal sign and start copying the lenght until the char ";" or '\0" be found. Sorry for my crap english, I am from Brasil and don't know that good english but I hope you all understand. I made a function to do that, but I would like to know if isn't there a standard one. Here is mine:
#define unsigned int B32U
#define char B8
B32U strsub(B8 *data, B8 *key) {
if (data && key) {
B8 *d = data;
B32U len = strlen(key), p = 0;
if (len > strlen(d))
return (0);
while (*d != '\0') {
if (*(d + len) != '\0') {
B32U x = 0;
while (x < len) {
if (key[x] == *d) {
*d++;
p++;
} else
break;
x++;
}
if (x == len)
return (p);
} else {
if (len == 1)
if (*d == key[0])
return (p);
B32 x = 0;
while (x < len) {
if (key[x] == *d) {
*d++;
p++;
} else
return (0);
x++;
}
return (p);
}
p++;
*d++;
}
}
return (0);
}
These defines are really problematic and the code does not compile:
#define unsigned int B32U
#define char B8
With the above definition, you do not define B32U as a preprocessor macro, but unsigned and it will expand to int B32U, not what you intended.
You should instead use typedef to define these types:
typedef unsigned int B32U;
typedef char B8;
Or not define these types at all and use standard types.
You can use strstr to write a simple function that returns a pointer to the end of the match or NULL is no match was found:
#include <string.h>
char *strstr_end(const char *s1, const char *s2) {
char *p = strstr(s1, s2);
if (p)
p += strlen(s2);
return p;
}
If you insist on returning the offset from the beginning of the string, you could return a signed type with value -1 if there is no match and the offset of the end if there is a match. ptrdiff_t is an good type for this:
#include <stddef.h>
#include <string.h>
ptrdiff_t strstr_endpos(const char *s1, const char *s2) {
char *p = strstr(s1, s2);
if (p)
return p - s1 + strlen(s2);
else
return -1;
}
To solve your problem you can use :
char *strrchr(const char *str, int c)
This function (which is in string.h) will return the adress of the last occurrence of the character c (';' or '\0' in your case) in the string str. However you only can find a char, not a string.
I have created a function for strend, which basically returns 1 if string t is present at the end of string s, however it never returns 1:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int strend(char *s, char *t) {
int p;
for (p = 0; p < strlen(s) - strlen(t); p++) {
*s++;
}
printf("%s\n%s\n", s, t);
if (s == t)
return 1;
return 0;
}
int main(void) {
int bool = strend("Hello", "ello");
printf("%i\n", bool);
return 0;
}
This gives me an output of:
ello
ello
0
So technically I should get 1. I assume the comparison using pointers is not used in this way?
You need to review your basic knowledge of C strings. There are lots of standard string functions in string.h that can help you with this test.
The basic problem is that the test s == t is valid, but you are comparing memory addresses here. You can see that is valid if you change the strings to test to
char test[] = "Hello";
int bool = strend_(test, test+1);
where test obviously is the same as your "Hello", and similarly, test+1 is the same as "ello" (try it by printing them). This correctly returns 1 with your routine.
In addition, I get two warnings:
on *s++; "warning: expression result unused [-Wunused-value]": you increment s but also ask what character is at that position through *s; and you don't use that information.
Fix by removing the * there.
on p < strlen(s) ..; "warning: comparison of integers of different signs: 'int' and 'unsigned long'", because strlen does not return a signed integer but an unsigned one (apparently, my header uses unsigned long).
Fix by declaring p as unsigned long, or even better, size_t.
Your entire routine can be condensed to a simple
int strend (char *s, char *t)
{
if (strlen(s) >= strlen(t) && !strcmp (s+strlen(s)-strlen(t),t))
return 1;
return 0;
}
It's not worth the trouble to cache the result of those four strlen calls into 2 temporary variables; a good compiler will work it out and do that for you. (A quick glance to the assembly output of the compiler I'm using – clang – shows it does, even with the default optimization settings.)
A slightly modified test, based on #M.M.'s comment:
int strend (char *s, char *t)
{
if (strlen(s) < strlen(t)) return 0;
return !strcmp (s+strlen(s)-strlen(t),t);
}
but attempting to optimize it this way is not as easy parsed as the routine above, and its assembly is ever so slightly "wordy" as well. Personally, I'd go for the more humanly readable version.
Use strcmp(3)
if (strcmp(s, t) == 0) return 1;
This actually compares the contents of the memory pointed to by s and t rather than their addresses.
Your code is broken in multiple ways:
The initial loop is a very cumbersome way to advance p by the difference of lengths if positive.
Once you have pointers at the same distance from the end of both strings, You should compare the characters with strcmp() (or memcmp() if you can first exclude the case of strlen(s) < strlen(t).
Comparing the pointers obtained after the loop will only work if t points inside the string pointed to by s, a special case that may or may not be produced by the compiler for the specific call in main: strend("Hello", "ello");.
Here is a modified version:
#include <string.h>
int strend(const char *str1, const char *str2) {
size_t len1 = strlen(str1);
size_t len2 = strlen(str2);
return len1 >= len2 && !memcmp(str1 + len1 - len2, str2, len2);
}
I corrected/modified your code, here is the code,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#pragma warning(disable:4996)
int strend(char *s, char *t)
{
int p,flag=0,count=0;//count will be the starting index for *t
p = strlen(s) - strlen(t);//this will be the starting index for *s
while(count<strlen(t))
{
if (*(s+p) == *(t+count))
{
flag = 1;
count++;
p++;
continue;
}
else
{
flag = 0;
break;
}
}
return flag;
}
int main(void)
{
int flag = strend("Hello", "ello");
printf("%i\n", flag);
return 0;
}
This code works too.
#include <stdio.h>
#include <string.h>
int strend (char *s1, char *s2);
void main ()
{
char str1[20] = "somethings";
char str2[20] = "things";
int f;
f = strend (str1,str2);
if (f==1)
printf ("1");
else
printf ("0");
}
int strend (char *str1, char *str2)
{
int l = strlen(str1) - strlen(str2);
str1 = str1 + l;
int d = strcmp(str1,str2);
if (d == 0)
return 1;
else
return 0;
}
this code works well.
int strend(char *s, char *t){
while(*t & *s){
if(*t == *s){
t++;
}
s++;
}
return *t==*s;
}
I wrote a function to compare 2 strings, return int as compare result, and pass an additional int pointer as param to retrieve the max match lengh.
// compare 2 strings
#include <stdio.h>
/**
* compare 2 string,
*
* #param sa
* string 1
* #param sb
* string 2
* #param len
* a int pointer pass from outside to store match length,
*
* return
* 0 if equlas, <0 if (a < b), >0 if (a > b),
*/
static int strCompare (char *sa, char *sb, int *len) {
for((*len)=0; *sa==*sb; sa++,sb++, (*len)++) {
// handle equals case, prevent ++ for \0,
if(!*sa)
break;
// printf("%c,%c\n", *sa, *sb);
}
return *sa - *sb;
}
int main(int argc, char *argv[]) {
if(argc < 3) {
printf("need 2 arguments.\n");
return 0;
}
int matchLen = 0;
int result = strCompare(argv[1], argv[2], &matchLen);
printf("compare:\n\t%s\n\t%s\nresult: %d\nmatch length: %d\n", argv[1], argv[2],
result, matchLen);
return 0;
}
Question:
I want the loop be more brief, e.g. avoid the if inside for, but didn't found out by myself, can anyone help to write a brief version with the same function interface.
(Please don't use libc function, I do this to improve my code style ;)
You might want to avoid the repeated reads and writes through the pointer while you are at it, and go for const-correctness:
static int strCompare (const char *sa, const char *sb, int *len) {
int tlen = 0;
while(*sa && *sa == *sb)
++tlen, ++sa, ++sb;
*len = tlen;
return *sa - *sb;
}
Or maybe better with restrict:
static int strCompare (const char *sa, const char *sb, int * restrict len) {
*len = 0;
while(*sa && *sa == *sb)
++*len, ++sa, ++sb;
return *sa - *sb;
}
BTW: The only thing making the code more efficient in the first case is avoiding the repeated writes through len.
In the second, it's using restrict and thus reducing aliasing (which will also remove all but the last write).
Also, consider whether size_t would not be a better type for the length.
Perhaps something like:
static int str_compare(const char *a, const char *b, size_t *len) {
const char *p = a;
for ( ; *p && *p == *b; ++p, ++b)
;
*len = p - a;
return *p - *b;
}
As Duplicator has mentioned use const for input strings.
Also size_t is widely used for sizes and counts, so likely better.
Alternative by tracking length:
static int str_compare(const char *a, const char *b, size_t *n) {
for (*n = 0; a[*n] && a[*n] == b[*n]; ++*n)
;
return a[*n] - b[*n];
}
Does not look too good with all the indirection on n, but still.
As a side note; you should return 1 (or something other then 0) on error (in main).
In your code if condition is needed. Because you are checking the pointer. If you accessing the pointer that is not allocate that will give you a segmentation fault. So avoid this you
have to do the if condition. Or else you can made that in the for loop.
for((*len)=0; *sa==*sb && *sa!='\0' ; sa++,sb++, (*len)++);
So avoiding the segmentation fault you need the another condition for checking.