ANSI C / C99 | Problem ze stworzeniem odpowiednika strdup

0

Witam,
Ucze sie ANSI C (uzywam sobie C99, bo prawde mowiac jak chce to i tak moge sie dostosowac do C89 a tak mi jest wygodniej). Chce korzystajac z semestru ANSI C dojsc do przyzwoitego poziomu w poslugiwaniu sie wskaznikami. Napisalem nastepujcy kod:

#include<stdio.h>
#include<stdlib.h>

int mystrlen(const char* buf)
{
  int chars = 0;
  while(*buf++)
    chars++;
      
  return chars;
}

int mystrcpy(char* target, const char* source)
{
  while(*source)
    *target++ = *source++;
}

char* mystrdup(const char* str)
{
  char* new = NULL;
  int length = mystrlen(str);
  if( (new = malloc(sizeof(char) * (length + 1))) == NULL ) {
    fprintf(stderr, "Cannot allocate memory!\n");
    return NULL;
  }
  
  while(*str) {
    *new = *str;
    new++;
    str++;
  }
  
  // nie rozumiem dlaczego nie wyswietli sie
  printf("%s\n", new);
  
  return new;
}

int main()
{
  const char* test = "Test string!";
  char* new = NULL;
  int length = mystrlen(test);
  
  new = malloc(sizeof(char) * (length + 1) );
  printf("Test: %d\n", length);
  printf("%s\n", test);
  
  mystrcpy(new, test);
  printf("%s\n", new);
  
  char* another = mystrdup(new);
  printf("%s\n", another);
  
  free(another);
  free(new);
  
  return 0;
}

Weźmy niedziałający fragment:

  while(*str) {
    *new = *str;
    new++;
    str++;
  }

Kazdy lancuch znakow w jezyku C powinien byc zakonczony '\0', ktorego wartosc liczbowa jest rowna 0. Zero to falsz, wiec jesli natrafimy na ten znak petla zakonczy sie.
Podajac nazwe tablicy np. 'char* new przez' new wskazujemy na jej 1 element (chyba ze wczesniej cos dodalismy do wskaznika). W przypadku lancuchow new i str nic wczesniej nie bylo dodawane. Dlaczego to sie nie chce kopiowac?

Chce, aby funkcja mystrdup zwrocila wskaznik na 1 element tablicy char*. I w ten sposob uzyskam dostep do lancucha znakow zapisanego gdzies na stercie. Oczywiscie musze pamietac o tym, ze nie mam garbage collectora i musze wywolac free().

0

Juz mam:

int mystrcpy(char* target, const char* source)
{
  while(*source)
    *target++ = *source++;
}

char* mystrdup(const char* str)
{
  char* new = NULL;
  int length = mystrlen(str);
  if( (new = malloc(sizeof(char) * (length + 1))) == NULL ) {
    fprintf(stderr, "Cannot allocate memory!\n");
    return NULL;
  }
  
  while(*str) {
    *new = *str;
    new++;
    str++;
  }
  

  new = new - length;
  
  return new;
}

Ale wszelkie uwagi odnosnie kodu i tak mile widziane.

0

Użyj <``code=c``> bo new Ci się podświetla jako słowo kluczowe. :P

new = malloc(sizeof(char) * (length + 1))

sizeof(char) to gwarantowane 1. Zawsze. Nawet jeżeli bajt na Twojej architekturze ma 36 czy 64 bit, to i tak sizeof(char) == 1. Jeśli już koniecznie chcesz tam operator sizeof, to:

new = malloc(sizeof(*new) * (length + 1))

Dzięki temu gdybyś zmienił typ zmiennej new na inny, to nie musiałbyś już nic modzić przy malloc. Chociaz w tym przypadku... ;)

  while(*str) {
    *new = *str;
    new++;
    str++;
  }

To już prawie sprawa stylu, ale można to troszkę skrócić. :) No i kompilator niemal na pewno to zoptymalizuje, ale pamiętaj, że i++ i ++i działają troszkę inaczej. Nie widzę potrzeby post-inkrementacji w tej wersji kodu (zwracana wartość oryginalna nie jest do niczego potrzebna) - za to przy wersji skróconej - jak najbardziej. ;)
edit: Na dobrą sprawę w C nie będzie chyba różnicy przy pre- i post-inkrementacji, bo da się kod (i to jeszcze na poziomie źródła) łatwo przekształcić... Jednak warto sobie wyrobić nawyk używania pre-inkrementacji tam gdzie ona wystarcza, bo już w innych językach ze składnią opartą na C (choćby C++ czy PHP) post-inkrementacja może być wolniejsza (a na pewno nie będzie szybsza).

0

new = new - length-1;

return new;

1 użytkowników online, w tym zalogowanych: 0, gości: 1