2013-09-17 3 views
0

здесь является прототипом:создать свою собственную функцию MemSet в с

void *memset(void *s, int c, size_t n) 

первый я не уверен, если я должен что-то вернуть, потому что, когда я использую MemSet я сделать, например

memset(str, 'a', 5); 

вместо из

str = memset(str, 'a', 5); 

здесь, где я с моим кодом:

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); 
} 

Я не хочу использовать массив в этой функции, чтобы лучше понять указатель и память, так что я не получаю 2 вещи: - как скопировать Int C в символ на моей пустой указатель б - что условие использовать на моем пока, чтобы быть уверенным, что он остановится до '\ 0' char

Редактировать: мне было интересно, есть ли способ сделать эту функцию без кастинга?

+8

Вы не должен любить пространства, много приятеля .. – Maroun

+4

'' б ++ - это проблема, учитывая 'b' точки к' void', который не имеет известного размера. 'b = c;' - это большая проблема, которая, скорее всего, приведет к краху вашего приложения. – mah

+3

Это должно быть что-то вроде 'void ms (char * dst, size_t len, char val) {for (char * p = dst; p! = Dst + len; ++ p) * p = val; } ' –

ответ

5

как скопировать Int C в символ на моей пустой указатель б

Вы преобразовать указатель недействительным в беззнаковое указатель полукокса:

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); 
} 

какие условия использования на мое время, чтобы убедиться, что он остановился до «\ 0» char

memset должны доверять длине, которая передается. Memset должен работать на общей части памяти, а не только на завершающей 0 строке, поэтому такой проверки не должно быть.

Если вам все равно нужно будет проверить 0 байт. вы могли бы сделать

if (*p == 0) //or if(!*p) 
    break; 
+1

Здесь что-то не так: Первая версия имела 'p = c', которая должна быть' * p = c', затем @mah отредактировал ответ и полностью удалил назначение. –

+0

Где вы устанавливаете содержимое в c? –

+0

@MartinR вы правы; Я понял, что «p = c» ошибался, но не уделял достаточного внимания поиску намерения ... Я думал, что это была бродячая строка кода. Спасибо за хедз-ап! – mah

0
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); 
} 
+0

Аргумент не должен иметь тип 'char *', и вы не должны возвращать 'b' после того, как он будет увеличен. – LihO

+2

Вы не должны просто отправлять код в качестве своего ответа. Добавьте некоторое объяснение. – akluth

+0

@LihO У меня изменился код. Не относился к этому серьезно. Просто заметил * b = c для первого взгляда. Спасибо за указание. – TwoCode

1

Арифметика указателей основан на компенсируя указатель на размер типа он указывает. Перед тем, как начать приращение этого указателя, вы должны преобразовать его из void* на указатель на 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; 
} 

также отмечают, что memsetвозвращает указатель на области памяти с, так что вы должны вернуть исходный указатель (прежде чем вы начнете увеличивать его).

+0

Что делать, если c - 512? –

+0

@VivekS: Это неправильное использование 'memset' (ошибка вызывающего абонента). – LihO

+0

@VivekS Из стандарта: 'Функция memset копирует значение c (преобразуется в unsigned char) в каждый из первых n символов объекта, на который указывает s'. Этот ответ на 100% совместим со стандартным определением memset. – Lundin

1

Функции причины часто возвращают значение, чтобы вернуть состояние ошибки вызывающей функции. В функциях, связанных с памятью, это обычно тот же указатель, что и ваш результат (включая NULL). В вашем примере вы можете не использовать возвращаемое значение вашей функции my_memset, но обычно это потому, что оно может быть включено в оценку кода (не могу придумать лучшего слова для этого), например.

if(!my_memset((void *)str, 'a', 5)) 
{ 
    printf("An error occurred in my_memset()\n"); 
} 

или в макросе, например.вернуть указатель на конец памяти, где вы скопировали char:

#define INIT_MEM_PTR_END(a,x) (my_memset((void *)&(a), (x), sizeof(a)) + sizeof(a)) 

Это, вероятно, не является большим примером (плюс потенциальные проблемы, если a уже указатель, и т.д ...), но он показывает что вы можете повторно использовать результат без необходимости писать еще пару строк для оценки результата и так далее.

Вы должны также проверить свои указатели перед их разыменованием. Если, например, void *b имеет значение NULL, у вас будет ошибка сегментации.

Ничего плохого в передаче void *, кроме факта, что намерение функции может быть не таким ясным, как при передаче указателя на определенный тип данных. Убедитесь, что вы применили его к чему-то действительному, хотя внутри. Кроме того, эта функция может использоваться для установки любой памяти на конкретное шестнадцатеричное значение (через char) или все 0 довольно легко.

Казалось бы, в этом случае b следует отличать от того же типа, что и значение, которое вы пытаетесь скопировать, int; однако тогда аргумент len становится неясным: размер в байтах или количество раз c следует скопировать в указатель b?

Поскольку в вашем main() вы копируете char в эту ячейку памяти, то это как раз лучше, чтобы изменить свою c к char, отдать свой b к более char* и сделать len длину в байтах или количество раз c должно скопированы в *b. Избегайте двусмысленности.

Способ, которым вы его написали, он скопирует c количество раз, указанное len, или пока вы не встретите нулевой символ, в зависимости от того, что на самом коротком/скором времени. Это нормально, если это ваше намерение.

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); 
    } 
} 
1

Вы можете использовать устройство Duff, чтобы иметь еще лучшую производительность.

#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) 
0

Я попробовал одну реализации, как это:

void memset(void *b, int c, int len) 
    { 
     char *s = b; 

     while(len--) 
      *s++ = c; 
    } 
Смежные вопросы