2010-08-18 5 views
2

Je comprends que pour retourner une chaîne à partir d'une fonction, je dois retourner un pointeur. Ce que je ne comprends pas, c'est pourquoi un tableau char est traité différemment de, disons, entier, et est détruit lorsque vous quittez la fonction. C'est probablement parce que je viens d'un monde des langues de haut niveau, mais cela semble être tout aussi valable pour moi:Renvoyer des chaînes dans la fonction C, explication nécessaire

int x = 1; 
return x; 

char x[] = "hello"; 
return x; 
+0

Vous devriez montrer le cas d'utilisation que vous avez en tête --- je peux deviner, mais c'est une conjecture, et la réponse détaillée dépend de ce que vous voulez faire ... – dmckee

+0

Voici un bon exemple sur la façon de faire choses différentes avec des chaînes et des pointeurs dans C https://stackoverflow.com/a/46344713/5842403 – Joniale

Répondre

8

La raison est à la fois simple et subtile: Les fonctions C ne peuvent pas être déclarées pour retourner des tableaux.

Lorsque vous retournez un pointeur, comme ceci:

char *foo(void) 
{ 
    char x[] = "hello"; 
    return x; 
} 

Le return x; est pas fait retourner x. Il renvoie un pointeur vers le premier élément de x - c'est exactement la même chose que dire:

return &x[0]; 

Il devrait être plus clair pourquoi ce n'est pas correct - il est exactement ce analogue à:

int *foo(void) 
{ 
    int x = 100; 
    return &x; 
} 

il est cependant possible de revenir structures des fonctions - afin que vous puissiez retourner un tableau aussi longtemps qu'il enveloppé dans un struct. Ce qui suit est tout à fait OK:

struct xyzzy { 
    char x[10]; 
}; 

struct xyzzy foo(void) 
{ 
    struct xyzzy x = { "hello" }; 
    return x; 
} 


1. Ceci est une conséquence d'une règle de cas particulier pour les types de tableau.Dans une expression, si un tableau ne fait pas l'objet des opérateurs unaires & ou sizeof, il évalue un pointeur vers son premier élément. Essayer de cerner un tableau en C, c'est un peu comme essayer d'attraper le brouillard dans vos mains - il disparaît simplement, remplacé par un pointeur.

+0

J'ai compris votre réponse, mais je suis un peu confus. Dans le bloc de code # 1, C renvoie automatiquement un pointeur (par exemple convertit "return x;" en "return &x[0];" car nous avons déclaré la fonction comme celle qui renvoie un pointeur (en utilisant *), ou le code n'est-il pas valide? – snitko

+0

@snitko: C traite la même chose que 'return &x[0];' non pas à cause du type de retour, mais parce que (sauf deux exceptions spécifiques, mentionnées dans ma note de bas de page), 'x' est toujours traité dans une expression comme & x [ 0] ' – caf

+0

Il n'y a pas de" retour automatique ", essayez de retourner un booléen et il va exploser La raison pour laquelle cela fonctionne est que' char x [] 'est un" tableau "donc c'est un pointeur (!). Vous pouvez également utiliser 'char * x =" hello "' qui a exactement la même valeur que 'char x []', le '[]' est juste du sucre syntaxique. array "en mémoire –

3

Un entier est un type primitif, il est donc valeur est renvoyée en tant que telle. Cependant, en C, une chaîne est et non un type primitif, c'est pourquoi vous le déclarez comme un tableau de caractères. Et lorsque vous renvoyez un tableau, vous renvoyez en fait un pointeur sur le tableau d'origine, donc c'est une sorte de retour par référence, si vous voulez. Mais comme vous pouvez le voir, le pointeur vers char x[] n'est pas valide une fois que vous quittez la fonction.

+2

Donc, seuls les types primitifs dans C peuvent être retournés à partir de fonctions sans utiliser de pointeurs, est-ce correct? – snitko

+0

non, comme caf points, vous pouvez également renvoyer une structure. le fait est que vous renvoyez un pointeur vers quelque chose d'autre (votre tableau), et que quelque chose d'autre se trouve dans un espace volatile (le cadre de pile de la fonction). Une fois qu'il est parti, le pointeur n'est plus valide. – Javier

+0

@snitko: Non, les types d'agrégat peuvent aussi être renvoyés à partir de fonctions. Seuls les types de tableaux ne peuvent pas être renvoyés directement. – caf

1

Ce tableau char est alloué dans la portée de la fonction (plutôt que dynamiquement alloué par exemple par malloc()), il sera donc indisponible en dehors de cette portée.

Deux façons autour d'elle:

  1. déclare que tableau de caractères pour être static
  2. Allouer la mémoire tampon dans la fonction d'appel, en passant comme argument, cette fonction juste remplit.
+1

Si le tableau de caractères est statique, il est préférable d'utiliser uniquement cette fonction (la fonction ne renvoie jamais de références au tableau de caractères statiques à l'appelant de la fonction), sauf si vous avez besoin de beaucoup de problèmes de multithreading "hé, pourquoi ma corde a-t-elle changé sans raison apparente?" problèmes de type. Même s'il est simplement utilisé à l'intérieur de la fonction, l'avoir comme statique peut toujours causer des problèmes de multithreading. – George

+0

Oui, c'est tout à fait vrai. Ne faites pas cela si vous exécutez la fonction plus d'une fois, en particulier en multithreading. PS J'ai eu l'idée de http://vijayinterviewquestions.blogspot.com/2007/07/write-c-code-to-return-string-from.html – thomasrutter

2

Veuillez voir cette réponse détaillée J'ai ecrit environ this. Non seulement qu'en C, les variables qui sont créées dans le cadre des fonctions utilisent un tas de pile automatique où résident les variables et quand la fonction retourne, ce tas est détruit, c'est là que l'utilisation des variables locales surtout de type string ie char [] ou un pointeur vers une chaîne doit être alloué sur le tas à l'extérieur de la portée de la fonction, sinon, garbage sera retourné. Pour contourner ce problème, utilisez un tampon statique ou utilisez malloc.

+0

Je trouve cette réponse trompeuse en ce qui concerne les variables automatiques (pile). "le compilateur et l'éditeur de liens ont donné au nom du symbole une adresse mémoire de 0x1234." semble impliquer que les tableaux automatiques ont une adresse fixe à la compilation. Clairement, ce n'est pas correct. ils sont alloués sur la pile. Si elle était fixée au moment de la compilation, la récursivité serait impossible. Les tableaux statiques ont des adresses fixes. –

+0

@Matthew: Ne pas être pédant, c'est juste un exemple, c'est ma façon d'expliquer à un débutant complet..les différences dans les nuances des tableaux et des pointeurs .... :) – t0mm13b

Questions connexes