Bagaimana cara mengembalikan beberapa nilai dari fungsi di C?

89

Jika saya memiliki fungsi yang memberikan hasil intdan hasil string, bagaimana cara mengembalikan keduanya dari suatu fungsi?

Sejauh yang saya tahu, saya hanya dapat mengembalikan satu hal, sebagaimana ditentukan oleh tipe sebelum nama fungsi.

Tony Stark
sumber
7
Dengan stringmaksud Anda "Saya menggunakan C ++ dan ini adalah std::stringkelas" atau "Saya menggunakan C dan ini adalah char *pointer atau char[]larik."
Chris Lutz
baik, dalam kasus khusus saya, mereka adalah dua int: satu untuk 'skor' dari apa yang saya bandingkan, dan satu untuk 'indeks' di mana skor maksimal itu ditemukan. saya ingin menggunakan contoh string di sini hanya untuk kasus yang lebih umum
Tony Stark
Lewati string dengan referensi dan kembalikan int. Jalan tercepat. Tidak ada struct diperlukan.
Stefan Steiger
1
Bukankah fungsi yang mengembalikan 2 hasil melakukan lebih dari satu hal? Apa yang akan dikatakan Paman Bob?
Duncan

Jawaban:

124

Saya tidak tahu apa milik Anda string, tetapi saya akan berasumsi bahwa itu mengelola ingatannya sendiri.

Anda memiliki dua solusi:

1: Kembalikan a structyang berisi semua tipe yang Anda butuhkan.

2: Gunakan petunjuk untuk membagikan nilai.

Yang mana yang Anda pilih untuk digunakan sangat bergantung pada preferensi pribadi untuk semantik apa pun yang lebih Anda sukai.

Travis Gockel
sumber
7
Saya pikir itu lebih tergantung pada seberapa terkait nilai kembali. Jika int adalah kode kesalahan dan string adalah hasil, maka ini tidak boleh disatukan dalam struct. Itu konyol. Dalam hal ini, saya akan mengembalikan int dan meneruskan string sebagai a char *dan a size_tuntuk panjang kecuali sangat penting bagi fungsi untuk mengalokasikan string dan / atau return itu sendiri NULL.
Chris Lutz
@ Chris Saya setuju dengan Anda sepenuhnya, tetapi saya tidak tahu tentang semantik penggunaan variabel yang dia butuhkan.
Travis Gockel
Poin bagus Chris. Hal lain yang menurut saya perlu ditunjukkan adalah nilai vs referensi. Jika saya tidak salah mengembalikan struct seperti yang ditunjukkan pada contoh berarti salinan akan dibuat setelah dikembalikan, apakah itu benar? (Saya agak goyah pada C) Sementara metode lainnya menggunakan pass-by-reference dan karenanya tidak memerlukan alokasi lebih banyak memori. Tentu saja, struct dapat dikembalikan melalui pointer dan berbagi manfaat yang sama, bukan? (pastikan untuk mengalokasikan memori dengan benar dan semua itu tentu saja)
RTHarston
@BobVicktor: C tidak memiliki semantik referensi sama sekali (yang eksklusif untuk C ++), jadi semuanya adalah nilai. Solusi dua penunjuk (# 2) melewatkan salinan penunjuk ke dalam fungsi, yang getPairkemudian dereferensi . Bergantung pada apa yang Anda lakukan (OP tidak pernah mengklarifikasi apakah ini sebenarnya pertanyaan C), alokasi mungkin menjadi perhatian, tetapi biasanya tidak di lahan C ++ (pengoptimalan nilai pengembalian menyimpan semua ini) dan di lahan C, data salinan biasanya terjadi secara eksplisit (melalui strncpyatau apapun).
Travis Gockel
@TravisGockel Terima kasih atas koreksinya. Saya mengacu pada fakta bahwa pointer digunakan, jadi ini tidak menyalin nilai, hanya membagikan apa yang sudah dialokasikan. Tetapi Anda benar saat mengatakan bahwa itu tidak benar disebut sebagai referensi lewat di C. Dan terima kasih juga untuk potongan pengetahuan hebat lainnya. Saya suka mempelajari hal-hal kecil tentang bahasa ini. :)
RTHarston
10

Option 1: Mendeklarasikan struct dengan int dan string dan mengembalikan variabel struct.

Option 2: Anda dapat meneruskan salah satu dari keduanya melalui pointer dan membuat perubahan pada parameter sebenarnya melalui pointer dan mengembalikan yang lain seperti biasa:

atau

Option 3: Mirip dengan opsi 2. Anda dapat meneruskan keduanya melalui penunjuk dan tidak mengembalikan apa pun dari fungsi:

codaddict
sumber
Mengenai opsi 2, Anda juga harus memasukkan panjang senar. int fun(char *param, size_t len)
Chris Lutz
Sekarang itu tergantung pada fungsi yang dilakukan. Jika kita tahu hasil seperti apa yang dimasukkan fungsi ke dalam array char, kita bisa mengalokasikan ruang yang cukup untuk itu dan meneruskannya ke fungsi. Tidak perlu melewati panjangnya. Sesuatu yang mirip dengan cara kami menggunakan strcpymisalnya.
codaddict
7

Karena salah satu jenis hasil Anda adalah string (dan Anda menggunakan C, bukan C ++), saya sarankan meneruskan pointer sebagai parameter output. Menggunakan:

dan menyebutnya seperti ini:

Secara umum, lebih suka melakukan alokasi dalam fungsi pemanggilan , bukan di dalam fungsi itu sendiri, sehingga Anda bisa seterbuka mungkin untuk strategi alokasi yang berbeda.

Jesse Beder
sumber
6

Dua pendekatan berbeda:

  1. Meneruskan nilai yang Anda kembalikan dengan pointer, dan mengubahnya di dalam fungsi. Anda mendeklarasikan fungsi Anda sebagai void, tetapi mengembalikan melalui nilai yang diteruskan sebagai pointer.
  2. Tentukan struct yang menggabungkan nilai kembalian Anda.

Saya pikir # 1 sedikit lebih jelas tentang apa yang terjadi, meskipun itu bisa membosankan jika Anda memiliki terlalu banyak nilai kembali. Dalam hal ini, opsi # 2 bekerja dengan cukup baik, meskipun ada beberapa beban mental yang terlibat dalam membuat struct khusus untuk tujuan ini.

James Thompson
sumber
1
C tidak memiliki referensi ;-), meskipun karena poster digunakan string, mungkin aman untuk menggunakan C ++ ...
Travis Gockel
Benar-benar lupa tentang itu! Saya mengubah jawaban saya untuk menggunakan pointer, tetapi saya jelas sudah terlalu lama menggunakan C ++. :)
James Thompson
6

Buat struct dan setel dua nilai di dalamnya dan kembalikan variabel struct.

Anda harus mengalokasikan ruang untuk char *program Anda.

zs2020
sumber
3

Gunakan pointer sebagai parameter fungsi Anda. Kemudian gunakan untuk mengembalikan beberapa nilai.

Bloodlee
sumber
2

Dengan melewatkan parameter dengan mengacu pada fungsi.

Contoh:

Juga dengan menggunakan variabel global tetapi tidak disarankan.

Contoh:

Badr
sumber
4
void main(void)OH BAGAIMANA MEMBAKAR!
Chris Lutz
maksud kamu apa? @ Chris Lutz
Badr
6
mainseharusnya mengembalikan kode status. Di bawah * nix, lebih umum untuk mendeklarasikannya sebagai int main(int argc, char *argv[]), saya yakin Windows memiliki konvensi serupa.
Duncan
2

Salah satu pendekatannya adalah dengan menggunakan makro. Tempatkan ini di file headermultitype.h

Ini memungkinkan untuk mengembalikan hingga empat variabel dari suatu fungsi dan menetapkannya hingga empat variabel. Sebagai contoh, Anda dapat menggunakannya seperti ini:

Ini yang dicetaknya:

Solusinya mungkin tidak portabel karena memerlukan C99 atau yang lebih baru untuk makro variadic dan deklarasi variabel untuk pernyataan. Tapi menurut saya cukup menarik untuk memposting di sini. Masalah lainnya adalah kompilator tidak akan memperingatkan Anda jika Anda menetapkan nilai yang salah, jadi Anda harus berhati-hati.

Contoh tambahan, dan versi kode berbasis tumpukan menggunakan serikat pekerja, tersedia di repositori github saya .

Klas. S
sumber
1
Masalah portabilitas yang lebih besar adalah fitur non-standar__typeof__
MM
Alih-alih typeof, Anda mungkin bisa menggunakan sizeof. Dapatkan ukuran nilai yang dikembalikan dan alokasikan array yang cukup besar untuk menyimpan semuanya. Kemudian Anda bisa mengembalikannya.
Klas. S