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?
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(constchar*src){char*dst = malloc(strlen (src)+1);// Space for length plus nulif(dst == NULL)return NULL;// No memory
strcpy(dst, src);// Copy the charactersreturn dst;// Return the new string}
Em outras palavras:
Ele tenta alocar memória suficiente para conter a cadeia antiga (mais um caractere '\ 0' para marcar o final da cadeia).
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) .
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(constchar*src){size_t len = strlen(src)+1;// String plus '\0'char*dst = malloc(len);// Allocate spaceif(dst == NULL)return NULL;// No memory
memcpy (dst, src, len);// Copy the blockreturn dst;// Return the new string}
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(constchar* 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()).
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.
É 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.
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.
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.
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.
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).
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,
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.
strdupa
é perigoso e não deve ser usado, a menos que você já tenha determinado questrlen
é muito pequeno. Mas então você pode simplesmente usar uma matriz de tamanho fixo na pilha.strdup
/strdupa
em polonês?Respostas:
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:
Em outras palavras:
Ele tenta alocar memória suficiente para conter a cadeia antiga (mais um caractere '\ 0' para marcar o final da cadeia).
Se a alocação falhar, ele define
errno
aENOMEM
e retornaNULL
imediatamente. Definirerrno
comoENOMEM
é algo quemalloc
faz no POSIX, portanto não precisamos explicitamente fazê-lo no nossostrdup
. Se você não é compatível com POSIX, a ISO C não exige a existência de,ENOMEM
portanto, não a incluí aqui (b) .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
str
e uma letra minúscula são reservadas pelo padrão para instruções futuras. DeC11 7.1.3 Reserved identifiers
:As instruções futuras para
string.h
podem ser encontradas emC11 7.31.13 String handling <string.h>
: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:(c) Observe que eu uso
strcpy
para isso, pois mostra claramente a intenção. Em algumas implementações, pode ser mais rápido (já que você já sabe o tamanho) usarmemcpy
, 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:
fonte
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, usestrcpy
.{ EDOM, EILSEQ, ERANGE }
os códigos de erro necessários. Atualizei a resposta para explicar isso.Talvez o código seja um pouco mais rápido do que com,
strcpy()
pois o\0
char não precisa ser pesquisado novamente (já estava comstrlen()
).fonte
return memcpy(malloc(len), s, len);
como eu prefiro a falha na alocação em vez daNULL
falha na alocação.NULL
não precisa travar; é indefinido. Se você quiser ter certeza de que ela falha, escreva umaemalloc
chamadaabort
que falhe.emalloc
mesmo que não seja necessário, no Solaris ou Linux, para que você o utilize no futuro quando escrever código em outras plataformas.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.fonte
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.strdup
função como uma extensão. Em tal implementação, não há garantia de que issostrdup
se 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 fornecerchar *strdup(char *)
razões históricas e rejeitar tentativas de passar aconst char *
.Do strdup man :
A
strdup()
função retornará um ponteiro para uma nova string, que é uma duplicata da string apontada pors1
. O ponteiro retornado pode ser passado parafree()
. Um ponteiro nulo será retornado se a nova sequência não puder ser criada.fonte
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:
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.
fonte
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.
fonte
strdup
estrndup
são definidos em sistemas compatíveis com POSIX como: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,
NULL
será retornado eerrno
definido comoENOMEM
.A função strndup () copia no máximo
len
caracteres da sequênciastr
sempre nula, finalizando a sequência copiada.fonte
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).
fonte
A declaração:
é equivalente a (além do fato de que isso altera os ponteiros):
Enquanto que:
é equivalente a:
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,fonte
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.
fonte
strdup
não precisa ser uma constante de string, deve ser uma string C, ou seja, uma matriz terminada nula dechar
.