tags:

views:

231

answers:

10

Hi, I am writing the memset function and my code is below, I am having a problem

void* memsetFun(void* pointer, int c, int size) {

  if ( pointer != NULL && size > 0 ) {

    unsigned char* pChar =  pointer;


    int i = 0;

      for ( i = 0; i < size; ++i) {

      unsigned char temp = (unsigned char) c;

      *pChar++ = temp; // or pChar[i] = temp (they both don't work)

    }
  }  
    return pointer;


}

I also tried pChar[i] = the value we want and still not working. It gives me some trash numbers that do not make any sense.

And I am calling it:

memsetFun(address, num, size);
printf("value at %p is %d\n", address, *((int*) address));

Where I call the address (I just input the address)

For example, if you to print the chars ( c ) it prints like a weird char that looks like ( for the value 4 )

0 0
0 4
A: 

return p; prevents this from compiling: p is not defined.

A minor efficiency issue—in practice it would have little effect, since any good compiler would rearrange it, but coding perfectionists wouldn't allow it to remain—the assignment to temp is inside the loop, but it is the same assignment every time. That is, the assignment to temp can be moved before the loop.

wallyk
I edited it to pointer :) thank you but that is not the problem, that was just a copy, paste issue
A: 

You return p, which isn't defined/doesn't point to anything in particular. Maybe you meant pointer?

ty
it is pointer (edited that) :)
A: 

The code is logically correct. With the p => pointer change it works correctly.

Clarify how exactly it is "not working". Perhaps you are not understanding what it is supposed to do?

Alex
it is putting trash numbers into the values, so when u check the value (when u asked the value to be 2 for example), you check the value for the bytes assigned and the values come out to be random numbers
@unknown Can we see the code you are using to check the values?
Mic
I just edited my entry and u can see that now :)
A: 

You are probably getting trash numbers because you are casting from an int (4 bytes) to an unsigned char (1 byte), so if c > 255 or < 0 you won't be memsetting the values you are expecting to be.

mcdave
c is guaranteed to be between 0 and 255
A: 

Your function, as is, works for me.

I suppose you're calling it wrong. I call it like this

char a[100];
memsetFun(a, 0, sizeof a);
int b[100];
memsetFun(b, 0, sizeof b);

How are you calling your memsetFun()?

Edit

With

int b[100];
memsetFun(b, 9, sizeof b);

as an int is made up of 4 bytes (on my system) each value will be set to 0x09090909 or 151587081.

pmg
I just edited the entry to have how i call it :)
A: 

I ran a test if your program setting the memory of an int vector of 5 elements setting with the value 0x01.

The problem here is that you are iterating in a vector of int for example (which is 4 bytes) but iterating over it using char pointer arithmetic (1 byte). If you want to memset 0x01 for example you will write this number per value in the vector: 00000001000000010000000100000001 which gives me the same value using the original memset.

Andres
`memset` in the C language is defined to take `int` as the second parameter. You are assuming that an `int` is 4 bytes - this need not be true. Finally, I don't know what you're trying to say with the bit-pattern.
Alok
Well, run the program yourself. Suppose a vector int v[5]; after that memset(v, 0x01, sizeof(int)*5); memset will write 0x01010101 in your vector which seems to be wrong (some people may expect 0x01 per position) but its not true. Yes you pass a int for the value, but a pointer void as the mem buffer.
Andres
About the bit pattern, as you may now 1 in decimal is equal to 0x01 in hex which is equal to 00000001 in binary ;). That big binary pattern, with some effort, is the number 0x01010101 in hex or 16843009 in decimal
Andres
The way `memset` is defined, it *should* set the memory to 0x01010101 in this case. `memset`, by definition, writes only *one* value to all the memory locations that it writes to.
Alok
+4  A: 

Your code looks fine to me and several people here have commented that it works on their system.

So the obvious thing to do is to debug it - that's a skill that will come in handy quite a bit in future :-) You should learn it now.

What does the following code output when you run it?

void* memsetFun(void* pointer, int c, int size) {
    printf("A %x %d %d\n", pointer, c, size);
    if ( pointer != NULL && size > 0 ) {
        printf("B\n");
        unsigned char* pChar =  pointer;
        int i = 0;
        for ( i = 0; i < size; ++i) {
            printf("C %d (%d)", i, *pChar);
            unsigned char temp = (unsigned char) c;
            *pChar++ = temp; // or pChar[i] = temp (they both don't work)
            printf(" -> (%d)", i, *(pChar-1));
        }
    }  
    printf("D\n");
    return pointer;
}

From the output, it should be clear what paths the code is taking and what your parameters are (which will greatly assist the debugging process).

Update:

If you're filling your memory block with anything other than zeros and using this:

printf("value at %p is %d\n", address, *((int*) address));

to print it out, you will get strange results.

You're basically asking for a number of those bytes to be interpreted as an integer. So, for example, if you filled it with 0x02 bytes and you have a 4-byte integer type, you will get the integer 0x02020202 (33686018), not 0x02 as you may expect. If you want to see what the first character value is, use:

printf("value at %p is %d\n", address, *((char*) address));

And based on your latest question update:

For example, if you to print the chars ( c ) it prints like a weird char that looks like ( for the value 4 )
0 0
0 4

If that's a single character and you're printing it as a character, there's probably nothing wrong at all. Many output streams will give you that for a control character (CTRL-D in this case, ASCII code 4). If you instead filled it with ASCII code 0x30 (48), you would see the character '0' or ASCII 0x41 (65) would give you 'A'.

paxdiablo
I changed it but it is still giving me the same error ( and yes it gives me the value 33686018 when it is supposed to be 2 but even after changing that code to your code :( )
33686018 is 0x02020202, which is 2 repeated 4 times. Everything is fine, except your understanding of memory. :-)
Alok
Thanks Alok :) that's why I am trying to learn more. Anyway, I know that 33686018 is 0x02020202 but the problem is why I am getting it.
@unknown, have a look at the section of this answer immediately followint "Update:". You have a memory block where every character is 0x02 but you are printing an integer from that memory block. An integer in your case is 4 characters, *not* one. That's why you're getting the value 0x02020202. If you print a *char* from that block, you'll get the value you expect.
paxdiablo
`memset` can only set one value per byte. So, given 0x02, it sets that value on all the bytes. Later, you *interpret* 4 of these bytes as an `int`, and print it. If you interpreted 2 of these bytes, you would get `514` as output. So, your interpretation was wrong. Also, *please* see my answer to your question: it has useful information not only for this question, but for all the questions you want to ask in the future. Thanks!
Alok
A: 

That is exactly what it's supposed to do. Your function is working perfectly fine. The value "0x4" is not the ASCII character '4'.

Anon.
+1  A: 

As pointed out already, your function works as it should. Here is a complete example:

#include <assert.h>
#include <string.h>

void* memsetFun(void* pointer, int c, int size) {
    if ( pointer != NULL && size > 0 ) {
        unsigned char* pChar =  pointer;
        int i = 0;
        for ( i = 0; i < size; ++i) {
            unsigned char temp = (unsigned char) c;
            *pChar++ = temp; // or pChar[i] = temp (they both don't work)
        }
    }
    return pointer;
}

int main() {
    // Your memset
    char a[10];
    memsetFun(a, 'A', sizeof(a));

    // Uses system memset for verification
    char b[10];
    memset(b, 'A', sizeof(b));

    assert(sizeof(a) == sizeof(b));
    assert(memcmp(a, b, sizeof(b)) == 0);
    return 0;
}
Mic
A: 

It turned out that your memsetFun was correct, but your understanding of it was incorrect. You were asked repeatedly to show us the full code, but you didn't. You didn't even show us the actual input values you used in your call. From this, I hope you learn that:

  • When we ask for full code, we mean it.
  • If your code is really long, you should isolate the problem to a minimal program, which is still compilable, and post it.
  • You should not say "it doesn't work"; instead, you should tell us exactly how it doesn't work. What did you expect it to do? What did it do?
  • When you post code, copy-paste it. This will allow you to avoid errors like return p; when you wanted return pointer;.

Please understand that we are all trying to help you (and others), and the first step in the process is for you to help us help you by providing accurate information.

Finally, I have two comments about your memsetFun:

  • You should rename it to something else: names beginning with mem and followed by a lowercase letter are reserved for the C language.
  • You should change the type of the third parameter to size_t, because that is how memset is defined.

If your instructor gave you the function name and/or prototype, you should talk to him about it.

Alok
Where in the C standard does it say mem[a-z]* is reserved?
paxdiablo
C89, section 4.3.8:*Function names that begin with str , mem , or wcs and a lower-case letter (followed by any combination of digits, letters and underscore) may be added to the declarations in the <string.h> header.*But I was wrong. This is only true if string.h is included.
Alok
Interestingly, that's not so in c1x. The c1x text for "Future library directions" reads "All external names described below are reserved no matter what headers are included by the program." which makes it more stringent. But on further googling, that same phrase is apparently in c90. So I don't think you *are* wrong.
paxdiablo
Thanks for the references. I can't use C99 because gcc does not support it fully. I haven't found a free compiler/library collection that fully supports C99 yet. :-)
Alok