strdup () - o que faz em C?

302

Qual é o objetivo da strdup()função em C?

Manoj Dúvidas
fonte
44
também existe strdupa () (na biblioteca GNU C), uma boa função semelhante ao strdup (), mas aloca memória na pilha. Seu programa não precisa liberar a memória explicitamente como no caso com strdup (), ele será liberado automaticamente quando você sair da função onde strdupa () foi chamado
dmityugov
11
strdupaé perigoso e não deve ser usado, a menos que você já tenha determinado que strlené muito pequeno. Mas então você pode simplesmente usar uma matriz de tamanho fixo na pilha.
R .. GitHub Pare de ajudar o gelo
4
@slacker google translate não está sendo útil ... O que significa strdup/ strdupaem polonês?
precisa saber é o seguinte
14
@haneefmubarak here
anatolyg
Aqui está a diferença entre strdup e strcpy stackoverflow.com/questions/14020380/strcpy-vs-strdup
Siva Prakash

Respostas:

372

Exatamente como isso soa, supondo que você esteja acostumado à maneira abreviada pela qual C e UNIX atribuem palavras, ele duplica as strings :-)

Tendo em mente que, na verdade, não faz parte do próprio padrão ISO C (a) (é uma coisa POSIX), está efetivamente fazendo o mesmo que o código a seguir:

char *strdup(const char *src) {
    char *dst = malloc(strlen (src) + 1);  // Space for length plus nul
    if (dst == NULL) return NULL;          // No memory
    strcpy(dst, src);                      // Copy the characters
    return dst;                            // Return the new string
}

Em outras palavras:

  1. Ele tenta alocar memória suficiente para conter a cadeia antiga (mais um caractere '\ 0' para marcar o final da cadeia).

  2. Se a alocação falhar, ele define errnoa ENOMEMe retorna NULLimediatamente. Definir errnocomo ENOMEMé algo que mallocfaz no POSIX, portanto não precisamos explicitamente fazê-lo no nosso strdup. Se você não é compatível com POSIX, a ISO C não exige a existência de, ENOMEMportanto, não a incluí aqui (b) .

  3. Caso contrário, a alocação funcionou, então copiamos a string antiga para a nova string (c) e retornamos o novo endereço (que o chamador é responsável por liberar em algum momento).

Lembre-se de que é a definição conceitual. Qualquer escritor de biblioteca que mereça seu salário pode ter fornecido um código altamente otimizado direcionado ao processador específico que está sendo usado.


(a) No entanto, as funções que começam com stre uma letra minúscula são reservadas pelo padrão para instruções futuras. De C11 7.1.3 Reserved identifiers:

Cada cabeçalho declara ou define todos os identificadores listados em sua sub-cláusula associada e * opcionalmente declara ou define identificadores listados em sua sub-cláusula de instruções futuras da biblioteca associada. **

As instruções futuras para string.hpodem ser encontradas em C11 7.31.13 String handling <string.h>:

Nomes de funções que começam com str, memou wcse uma letra minúscula podem ser adicionados às declarações no <string.h>cabeçalho.

Portanto, você provavelmente deveria chamar de outra coisa, se quiser estar seguro.


(b) A alteração seria basicamente substituída if (d == NULL) return NULL;por:

if (d == NULL) {
    errno = ENOMEM;
    return NULL;
}

(c) Observe que eu uso strcpypara isso, pois mostra claramente a intenção. Em algumas implementações, pode ser mais rápido (já que você já sabe o tamanho) usar memcpy, pois elas podem permitir a transferência de dados em partes maiores ou em paralelo. Ou talvez não :-) Mantra de otimização nº 1: "meça, não pense".

De qualquer forma, se você decidir seguir esse caminho, faria algo como:

char *strdup(const char *src) {
    size_t len = strlen(src) + 1;       // String plus '\0'
    char *dst = malloc(len);            // Allocate space
    if (dst == NULL) return NULL;       // No memory
    memcpy (dst, src, len);             // Copy the block
    return dst;                         // Return the new string
}
paxdiablo
fonte
8
Vale ressaltar que, como implica a implementação de amostra do Pax, strdup (NULL) é indefinido e não é algo que você pode esperar que se comporte de maneira previsível.
descontrair
2
Além disso, acho que malloc () definiria errno, portanto, você não precisa configurá-lo sozinho. Eu acho que.
7893 Chris Lutz
5
@Alcot, strdupé para aquelas situações em que você deseja alocar memória heap para a cópia da string. Caso contrário, você deve fazer isso sozinho. Se você já possui um buffer grande o suficiente (malloc'ed ou não), sim, use strcpy.
28412
2
@acgtyrant: se, por padrão, você quer dizer o padrão ISO (o padrão C real), não, não faz parte dele. Ele é parte do padrão POSIX. No entanto, existem muitas implementações em C que a fornecem, apesar de não serem uma parte oficial da ISO C. No entanto, mesmo que não o fizessem, os cinco alunos desta resposta deveriam ser mais do que suficientes.
paxdiablo
2
Bom ponto, @chux, ISO exige apenas { EDOM, EILSEQ, ERANGE }os códigos de erro necessários. Atualizei a resposta para explicar isso.
21418 Paxdiablo
86
char * strdup(const char * s)
{
  size_t len = 1+strlen(s);
  char *p = malloc(len);

  return p ? memcpy(p, s, len) : NULL;
}

Talvez o código seja um pouco mais rápido do que com, strcpy()pois o \0char não precisa ser pesquisado novamente (já estava com strlen()).

Patrick Schlüter
fonte
Obrigado. Na minha implementação pessoal, eu o tornei "pior". return memcpy(malloc(len), s, len);como eu prefiro a falha na alocação em vez da NULLfalha na alocação.
Patrick Schlüter
3
A desreferenciação @tristopia NULLnão precisa travar; é indefinido. Se você quiser ter certeza de que ela falha, escreva uma emallocchamada abortque falhe.
Dave
Eu sei disso, mas minha implementação é garantida para ser executada apenas no Solaris ou Linux (pela própria natureza do aplicativo).
Patrick Schlüter
@tristopia: É bom ter o hábito de fazer as coisas da melhor maneira. Adquira o hábito de usar, emallocmesmo que não seja necessário, no Solaris ou Linux, para que você o utilize no futuro quando escrever código em outras plataformas.
ArtOfWarfare 28/02
51

Não adianta repetir as outras respostas, mas observe que ele strdup()pode fazer o que quiser da perspectiva C, pois não faz parte de nenhum padrão C. No entanto, é definido pelo POSIX.1-2001.

Chris Young
fonte
4
É strdup()portátil? Não, não disponível em ambiente não POSIX (trivialmente implementável de qualquer maneira). Mas dizer que uma função POSIX pode fazer qualquer coisa é bastante pedante. O POSIX é outro padrão tão bom quanto o C e ainda mais popular.
PP
2
@BlueMoon Eu acho que o ponto é que uma implementação C que não reivindica conformidade com o POSIX ainda pode fornecer uma strdupfunção como uma extensão. Em tal implementação, não há garantia de que isso strdupse comporte da mesma maneira que a função POSIX. Não conheço nenhuma dessas implementações, mas uma implementação não maliciosa legítima pode fornecer char *strdup(char *)razões históricas e rejeitar tentativas de passar a const char *.
Qual é a diferença entre o padrão C e o POSIX? Por padrão C, você quer dizer que ele não existe nas bibliotecas padrão C?
Koray Tugay 22/03
@KorayTugay Eles são padrões diferentes. É melhor tratá-los como não relacionados, a menos que você saiba que o padrão para uma função C específica está em conformidade com o padrão POSIX e que seu compilador / biblioteca está em conformidade com o padrão para essa função.
Mateus Leia
17

Do strdup man :

A strdup()função retornará um ponteiro para uma nova string, que é uma duplicata da string apontada por s1. O ponteiro retornado pode ser passado para free(). Um ponteiro nulo será retornado se a nova sequência não puder ser criada.

VonC
fonte
4

strdup () faz alocação dinâmica de memória para a matriz de caracteres, incluindo o caractere final '\ 0' e retorna o endereço da memória heap:

char *strdup (const char *s)
{
    char *p = malloc (strlen (s) + 1);   // allocate memory
    if (p != NULL)
        strcpy (p,s);                    // copy string
    return p;                            // return the memory
}

Portanto, o que ele faz é nos dar outra string idêntica à string fornecida por seu argumento, sem exigir que alocemos memória. Mas ainda precisamos liberá-lo mais tarde.

Karshit
fonte
3

Ele faz uma cópia duplicada da string transmitida executando um malloc e strcpy da string passada. O buffer malloc'ed é retornado ao chamador, daí a necessidade de executar livremente o valor de retorno.

jussij
fonte
3

strdupe strndupsão definidos em sistemas compatíveis com POSIX como:

char *strdup(const char *str);
char *strndup(const char *str, size_t len);

A função strdup () aloca memória suficiente para uma cópia da string str, faz a cópia e retorna um ponteiro para ela.

O ponteiro pode posteriormente ser usado como argumento para a função free.

Se houver memória insuficiente disponível, NULLserá retornado e errnodefinido como ENOMEM.

A função strndup () copia no máximo lencaracteres da sequência strsempre nula, finalizando a sequência copiada.

Sujay Kumar
fonte
1

A coisa mais valiosa que ele faz é fornecer outra string idêntica à primeira, sem exigir que você aloque a memória (local e tamanho). Mas, como observado, você ainda precisa liberá-lo (mas também não exige cálculo de quantidade).

dkretz
fonte
1

A declaração:

strcpy(ptr2, ptr1);

é equivalente a (além do fato de que isso altera os ponteiros):

while(*ptr2++ = *ptr1++);

Enquanto que:

ptr2 = strdup(ptr1);

é equivalente a:

ptr2 = malloc(strlen(ptr1) + 1);
if (ptr2 != NULL) strcpy(ptr2, ptr1);

Portanto, se você deseja que a string que você copiou seja usada em outra função (como é criada na seção heap), pode usar strdup, caso contrário, strcpyé suficiente,

Md. Al Amin Bhuiyan
fonte
0

A função strdup () é uma abreviação de duplicata de string, recebe um parâmetro como uma constante de string ou literal de string e aloca espaço suficiente para a string e grava os caracteres correspondentes no espaço alocado e, finalmente, retorna o endereço da alocada espaço para a rotina de chamadas.

AnkitSablok
fonte
1
O argumento para strdupnão precisa ser uma constante de string, deve ser uma string C, ou seja, uma matriz terminada nula de char.
chqrlie