C'deki bir işlevden birden çok değeri nasıl döndürürüm?


89

Sonuç intve sonuç üreten bir işleve sahipsem string, her ikisini de işlevden nasıl döndürürüm?

Anlayabildiğim kadarıyla, işlev adından önceki türe göre belirlendiği gibi yalnızca bir şeyi döndürebilirim.


7
By stringyapmak "Ben C ++ kullanıyorum ve bu demek std::stringsınıf" veya "Ben C kullanıyorum ve bu bir olan char *işaretçi veya char[]dizi."
Chris Lutz

benim özel durumumda, iki puan vardı: biri karşılaştırdığım şeyin 'puanı' için, diğeri ise bu maksimum puanın bulunduğu yerin 'endeksi' için. burada sadece daha genel durum için bir dize örneği kullanmak istedim
Tony Stark

Dizeyi referans olarak iletin ve int'i geri verin. En hızlı yol. Yapı gerektirmez.
Stefan Steiger

1
Birden fazla şey yaparak 2 sonuç döndüren bir işlev değil mi? Bob Amca ne derdi?
Duncan

Yanıtlar:


124

Senin ne olduğunu bilmiyorum string, ama kendi hafızasını yönettiğini varsayacağım.

İki çözümünüz var:

1: structİhtiyacınız olan tüm türleri içeren bir döndür.

2: Değerleri iletmek için işaretçiler kullanın.

Hangisini kullanmayı seçeceğiniz, büyük ölçüde hangi anlambilimden daha çok hoşlandığınız konusunda kişisel tercihinize bağlıdır.


7
Bence daha çok dönüş değerlerinin ne kadar ilişkili olduğuna bağlı. İnt bir hata koduysa ve dize bir sonuçsa, bunlar bir yapı içinde bir araya getirilmemelidir. Bu çok aptalca. Bu durumda, işlevin kendi dizesini ve / veya dönüşünü ayırması kesinlikle önemli olmadığı sürece , int'i döndürür ve dizeyi uzunluk için a char *ve a size_tolarak iletirim NULL.
Chris Lutz

@Chris Size tamamen katılıyorum, ancak ihtiyaç duyduğu değişkenlerin kullanım anlamsallığı hakkında hiçbir fikrim yok.
Travis Gockel

İyi nokta Chris. Dikkat çekmeye değer olduğunu düşündüğüm başka bir şey de değer ve referans. Yapıyı örnekte gösterildiği gibi iade etmekte yanılmıyorsam, iade edildiğinde bir kopya yapılacağı anlamına gelir, bu doğru mu? (C konusunda biraz titriyorum) Diğer yöntem referansa göre geçiş kullanır ve bu nedenle daha fazla bellek ayırmayı gerektirmez. Elbette, yapı işaretçi aracılığıyla iade edilebilir ve aynı faydayı paylaşabilir mi? (belleği düzgün ayırmaya dikkat ederek ve tabii bütün bunlar)
RTHarston

@BobVicktor: C'nin referans semantiği yoktur (bu C ++ 'ya özeldir), yani her şey bir değerdir. İki işaretçi çözümü (# 2), işaretçilerin kopyalarını bir işleve geçiriyor , bu da getPairdaha sonra başvurulardan vazgeçiyor . Ne yaptığınıza bağlı olarak (OP, bu gerçekten bir C sorusu olup olmadığını asla açıklığa kavuşturmadı), tahsis bir endişe olabilir, ancak genellikle C ++ arazisinde değildir (geri dönüş değeri optimizasyonu tüm bunları kaydeder) ve C alanında, veriler kopyalar genellikle açıkça (aracılığıyla strncpyveya her neyse) gerçekleşir.
Travis Gockel

@TravisGockel Düzeltme için teşekkürler. İşaretçilerin kullanıldığı gerçeğinden bahsediyordum, bu yüzden değerleri kopyalamak değil, sadece zaten tahsis edilmiş olanı paylaşmak. Ancak C de buna tam anlamıyla referansla geçiş denmediğini söylemekte haklısınız ve diğer büyük bilgi külçeleri için de teşekkürler. Dillerle ilgili bu küçük şeyleri öğrenmeyi seviyorum. :)
RTHarston

10

Option 1: Bir int ve string içeren bir yapı bildirin ve bir struct değişkeni döndürür.

Option 2: İkisinden birini işaretçi aracılığıyla geçirebilir ve işaretçi aracılığıyla gerçek parametrede değişiklikler yapabilir ve diğerini her zamanki gibi döndürebilirsiniz:

veya

Option 3: 2. seçeneğe benzer şekilde. Her ikisini de işaretçi aracılığıyla geçirebilir ve işlevden hiçbir şey döndüremezsiniz:


Seçenek 2 ile ilgili olarak, dizenin uzunluğunu da iletmelisiniz. int fun(char *param, size_t len)
Chris Lutz

Şimdi bu, işlevin ne yaptığına bağlı. İşlevin char dizisine ne tür bir sonuç girdiğini bilirsek, onun için yeterli alan ayırabilir ve onu işleve aktarabiliriz. Boyunu geçmeye gerek yok. strcpyÖrneğin kullandığımıza benzer bir şey .
codaddict

7

Sonuç türlerinizden biri bir dize olduğundan (ve C ++ değil, C kullandığınız için), işaretçileri çıktı parametreleri olarak iletmenizi öneririm. Kullanım:

ve şöyle diyelim:

Genel olarak, farklı tahsis stratejilerine mümkün olduğunca açık olabilmeniz için tahsisatı fonksiyonun içinde değil , çağıran fonksiyonda yapmayı tercih edin .


6

İki farklı yaklaşım:

  1. Dönüş değerlerinizi işaretçi ile aktarın ve fonksiyon içinde değiştirin. İşlevinizi geçersiz ilan edersiniz, ancak işaretçi olarak iletilen değerler aracılığıyla geri döner.
  2. Dönüş değerlerinizi toplayan bir yapı tanımlayın.

Bence 1 numaranın neler olduğu konusunda biraz daha açık olduğunu düşünüyorum, ancak çok fazla dönüş değeriniz varsa sıkıcı olabilir. Bu durumda, 2. seçenek oldukça iyi işliyor, ancak bu amaç için özel yapılar oluşturmanın bazı zihinsel yükleri olsa da.


1
Poster kullanılan beri rağmen C ;-) başvuruda bulunmadığını string, varsaymak güvenli olabilir C ++ ...
Travis Gockel

Bunu tamamen unuttum! Cevabımı işaretçiler kullanacak şekilde değiştirdim, ancak açıkça C ++ ülkesinde çok uzun süredir bulundum. :)
James Thompson

6

Bir yapı oluşturun ve içinde iki değer ayarlayın ve struct değişkenini döndürün.

Sen için yer ayırmak zorunda char *programınızda.


3

İşlev parametreleriniz olarak işaretçileri kullanın. Ardından birden çok değer döndürmek için bunları kullanın.


2

Parametreleri işleve başvurarak ileterek.

Örnekler:

Ayrıca global değişkenler kullanılarak, ancak tavsiye edilmez.

Misal:


4
void main(void)OH NASIL YAKAR!
Chris Lutz

ne demek istiyorsun? @ Chris Lutz
Badr

6
mainbir durum kodu döndürmesi gerekiyor. * Nix altında, int main(int argc, char *argv[])Windows'un benzer kurallara sahip olduğuna inanıyorum.
Duncan

2

Bir yaklaşım, makro kullanmaktır. Bunu bir başlık dosyasına yerleştirinmultitype.h

Bu, bir işlevden en fazla dört değişken döndürmeyi ve bunları en fazla dört değişkene atamayı mümkün kılar. Örnek olarak, bunları şu şekilde kullanabilirsiniz:

Bu, yazdırdığı şey:

Çözüm, değişken makrolar ve deyim için değişken bildirimleri için C99 veya sonrasını gerektirdiğinden taşınabilir olmayabilir. Ama buraya yazacak kadar ilginç olduğunu düşünüyorum. Diğer bir konu da derleyicinin yanlış değerleri atarsanız sizi uyarmamasıdır, bu yüzden dikkatli olmanız gerekir.

Ek örnekler ve birleşim kullanan kodun yığın tabanlı sürümü github depomda mevcuttur .


1
Daha büyük bir taşınabilirlik sorunu, standart olmayan özelliktir__typeof__
MM

Typeof yerine sizeof kullanabilirsiniz. Dönüş değerlerinin boyutunu alın ve hepsini depolamak için yeterince büyük bir dizi ayırın. O zaman iade edebilirsiniz.
Klas. S
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.