साइट कोडरबाइट पर 'हो जाता है (स्टडिन)' के साथ क्या हो रहा है?


144

कोडरबाइट एक ऑनलाइन कोडिंग चैलेंज साइट है (मुझे यह सिर्फ 2 मिनट पहले मिला था)।

आपके द्वारा अभिवादन की जाने वाली पहली C ++ चुनौती में C ++ कंकाल है जिसे आपको संशोधित करने की आवश्यकता है:

#include <iostream>
#include <string>
using namespace std;

int FirstFactorial(int num) {

  // Code goes here
  return num;

}

int main() {

  // Keep this function call here
  cout << FirstFactorial(gets(stdin));
  return 0;

}

यदि आप C ++ से पहले परिचित हैं, तो सबसे पहले * जो आपकी आंखों में चबूतरे है:

int FirstFactorial(int num);
cout << FirstFactorial(gets(stdin));

तो, ठीक है, कोड कॉल getsजो C ++ 11 के बाद से हटा दिया गया है और C ++ 14 के बाद हटा दिया गया है जो अपने आप में खराब है।

लेकिन तब मुझे एहसास होता है: getsप्रकार का है char*(char*)। तो यह एक FILE*पैरामीटर को स्वीकार नहीं करना चाहिए और परिणाम एक पैरामीटर के स्थान पर उपयोग करने योग्य नहीं होना चाहिए int, लेकिन ... न केवल यह किसी भी चेतावनी या त्रुटियों के बिना संकलित करता है, लेकिन यह चलता है और वास्तव में सही इनपुट मूल्य को पास करता है FirstFactorial

इस विशेष साइट के बाहर, कोड संकलन नहीं करता है (जैसा कि अपेक्षित है), तो यहां क्या हो रहा है?


* वास्तव में पहला है, using namespace stdलेकिन वह यहाँ मेरे मुद्दे के लिए अप्रासंगिक है।


ध्यान दें कि stdinमानक पुस्तकालय में एक है FILE*, और किसी भी प्रकार के लिए एक सूचक धर्मान्तरित char*, जो के तर्क का प्रकार है gets()। हालाँकि, आपको कभी भी, कभी भी, कभी भी किसी सी सी प्रतियोगिता के बाहर उस तरह का कोड नहीं लिखना चाहिए। यदि आपका कंपाइलर भी इसे स्वीकार करता है, तो अधिक चेतावनी झंडे जोड़ें, और यदि आप एक कोडबेस को ठीक करने की कोशिश कर रहे हैं, जिसमें इसका निर्माण है, तो चेतावनियों को त्रुटियों में बदल दें।
डेविसलर

1
@Davislor नहीं यह "उम्मीदवार फ़ंक्शन व्यवहार्य नहीं है: 1 तर्क के लिए 'संरचना _IO_FILE *' से 'char *' तक कोई भी ज्ञात रूपांतरण नहीं है
bolov

3
@ डेविलेर हुह, जो प्राचीन सी के लिए सच हो सकता है, लेकिन निश्चित रूप से सी ++ के लिए नहीं।
क्वेंटिन

@ क्वेंटिन हाँ। यह संकलन नहीं होना चाहिए। इरादा चुनौती हो सकता है, "इस टूटे हुए कोड को ले लो, मेरे दिमाग को पढ़ें कि यह क्या करना है, और इसे ठीक करना है," लेकिन इस मामले में एक वास्तविक विनिर्देश होना चाहिए। परीक्षण मामलों के साथ।
डेविसलर

6
मुझे आश्चर्य है कि किसी ने भी यह कोशिश नहीं की, लेकिन gets(stdin )(अतिरिक्त स्थान के साथ) अपेक्षित C ++ त्रुटि पैदा करता है।
रोमन ओडिसी

जवाबों:


174

मैं Coderbyte का संस्थापक हूं और वह व्यक्ति भी जिसने इस gets(stdin)हैक को बनाया है ।

इस पोस्ट की टिप्पणियां सही हैं कि यह ढूंढने और बदलने का एक रूप है, इसलिए मुझे यह बताने दें कि मैंने वास्तव में जल्दी क्यों किया।

उस दिन वापस जब मैंने पहली बार साइट बनाई थी (2012 के आसपास), इसने केवल जावास्क्रिप्ट का समर्थन किया। ब्राउज़र में चल रहे जावास्क्रिप्ट में "इनपुट में पढ़ने" का कोई तरीका नहीं था, और इसलिए एक फ़ंक्शन होगा foo(input)और मैंने readline()इसे कॉल करने के लिए Node.js से फ़ंक्शन का उपयोग किया foo(readline())। सिवाय मैं एक बच्चा था और बेहतर नहीं जानता था, इसलिए मैं सचमुच readline()रन-टाइम पर इनपुट के साथ बदल दिया । तो foo(readline())बन गया foo(2)या foo("hello")जो जावास्क्रिप्ट के लिए ठीक काम किया।

2013/2014 के आसपास मैंने अधिक भाषाओं को जोड़ा और ऑनलाइन कोड का मूल्यांकन करने के लिए तृतीय-पक्ष सेवा का उपयोग किया, लेकिन मेरे द्वारा उपयोग की जाने वाली सेवाओं के साथ स्टड / स्टडआउट करना बहुत मुश्किल था, इसलिए मैं उसी मूर्खतापूर्ण खोज और भाषाओं के लिए प्रतिस्थापित किया गया जैसे पायथन, रूबी, और अंततः C ++, C #, आदि।

आज के लिए तेजी से, मैं अपने खुद के कंटेनरों में कोड चलाता हूं, लेकिन स्टड / स्टडआउट के काम करने के तरीके को कभी भी अपडेट नहीं किया है क्योंकि लोगों को अजीब हैक करने की आदत हो गई है (कुछ लोगों ने मंचों में पोस्ट किया है, जिसमें बताया गया है कि इसे कैसे प्राप्त करें)।

मुझे पता है कि यह सबसे अच्छा अभ्यास नहीं है और यह किसी व्यक्ति के लिए हैक्स को इस तरह से देखने के लिए एक नई भाषा सीखने में मददगार नहीं है, लेकिन यह विचार नए प्रोग्रामर के लिए था कि वे इनपुट पढ़ने के बारे में चिंता न करें और हल करने के लिए एल्गोरिथ्म लिखने पर ध्यान दें। संकट। वर्षों पहले चुनौती देने वाली साइटों की कोडिंग के बारे में एक आम शिकायत यह थी कि नए प्रोग्रामर बहुत समय stdinबिताएंगे और यह पता लगाएंगे कि फाइल से लाइनों को कैसे पढ़ें या पढ़ें, इसलिए मुझे कोडरबीट पर इस समस्या से बचने के लिए नए कोडर चाहिए थे।

मैं संपूर्ण संपादक पृष्ठ को जल्द ही डिफ़ॉल्ट कोड और stdinभाषाओं के लिए पढ़ने के साथ अपडेट करूंगा । उम्मीद है कि तब C ++ प्रोग्रामर Coderbyte का उपयोग करने का अधिक आनंद लेंगे :)


20
"बी] विचार नए प्रोग्रामर के लिए था कि वे इनपुट पढ़ने के बारे में चिंता न करें और समस्या को हल करने के लिए एल्गोरिथ्म लिखने पर ध्यान केंद्रित करें" - और यह आपके साथ ऐसा नहीं हुआ, इसके बजाय कुछ ऐसा लिखा हो जो वास्तविक हो। "कोड, बस उस जगह में एक बनाया फ़ंक्शन नाम या एक स्पष्ट प्लेसहोल्डर है? वास्तव में जिज्ञासु।
रदर रेन्डमॉलेघ

25
जब मैं यह पोस्ट करता हूं, तो मुझे वास्तव में यह उम्मीद नहीं थी कि मैं खुद के अलावा कोई जवाब चुनने जा रहा हूं। इतने शानदार तरीके से मुझे गलत साबित करने के लिए धन्यवाद। आपके जवाब को देखना वाकई खुशी की बात है।
bolov

4
बहुत ही रोचक! मैं अनुशंसा करूंगा, यदि आप इस हैक को रखना चाहते हैं, ताकि आप फ़ंक्शन कॉल को कुछ के साथ बदल दें TAKE_INPUT, तो #define TAKE_INPUT whatever_hereशीर्ष पर सम्मिलित करने के लिए अपने खोज-प्रतिस्थापन का उपयोग करें ।
ड्रेकोनिस

18
हमें "मैं x का संस्थापक हूं और वह लड़का जिसने इसे बनाया है" के साथ शुरू होने वाले अधिक उत्तरों की आवश्यकता है ।
पाइप

2
@ जिहनी किसी ने भी इसे सही होने के लिए नहीं कहा। वास्तव में, मुझे विश्वास है कि लगभग कोई भी प्लेसहोल्डर कुछ से बेहतर होता जो किसी भी नौसिखिया के लिए मान्य कोड जैसा दिखता है लेकिन वास्तव में संकलन नहीं करता है।
रुथेर रेंदोमेलेघ

112

मैं बेचैन हूँ। इसलिए, जांच के चश्मे को लगाने का समय और चूंकि मेरे पास संकलक या संकलन झंडे तक पहुंच नहीं है, मुझे आविष्कारक होने की आवश्यकता है। इसके अलावा, क्योंकि इस कोड के बारे में कुछ भी समझ में नहीं आता है कि यह हर धारणा पर एक बुरा विचार सवाल नहीं है।

पहले वास्तविक प्रकार की जांच करते हैं gets। मैं उस के लिए एक छोटी सी चाल है:

template <class> struct Name;

int main() { 
    
    Name<decltype(gets)> n;
  
  // keep this function call here
  cout << FirstFactorial(gets(stdin));
  return 0;
    
}

और यह दिखता है ... सामान्य:

/tmp/613814454/Main.cpp:16:19: warning: 'gets' is deprecated [-Wdeprecated-declarations]
    Name<decltype(gets)> n;
                  ^
/usr/include/stdio.h:638:37: note: 'gets' has been explicitly marked deprecated here
extern char *gets (char *__s) __wur __attribute_deprecated__;
                                    ^
/usr/include/x86_64-linux-gnu/sys/cdefs.h:254:51: note: expanded from macro '__attribute_deprecated__'
# define __attribute_deprecated__ __attribute__ ((__deprecated__))
                                                  ^
/tmp/613814454/Main.cpp:16:26: error: implicit instantiation of undefined template 'Name<char *(char *)>'
    Name<decltype(gets)> n;
                         ^
/tmp/613814454/Main.cpp:12:25: note: template is declared here
template <class> struct Name;
                        ^
1 warning and 1 error generated.

getsके रूप में चिह्नित किया गया है और हस्ताक्षर हैं char *(char *)। लेकिन फिर FirstFactorial(gets(stdin));संकलन कैसे हो ?

चलो कुछ और कोशिश करते हैं:

int main() { 
  Name<decltype(gets(stdin))> n;
  
  // keep this function call here
  cout << FirstFactorial(gets(stdin));
  return 0;
    
} 

जो हमें देता है:

/tmp/286775780/Main.cpp:15:21: error: implicit instantiation of undefined template 'Name<int>'
  Name<decltype(8)> n;
                    ^

अंत में हमें कुछ मिल रहा है decltype(8):। तो पूरे gets(stdin)को इनपुट के साथ बदल दिया गया था ( 8)।

और चीजों को निराई मिलती है। संकलक त्रुटि जारी है:

/tmp/596773533/Main.cpp:18:26: error: no matching function for call to 'gets'
  cout << FirstFactorial(gets(stdin));
                         ^~~~
/usr/include/stdio.h:638:14: note: candidate function not viable: no known conversion from 'struct _IO_FILE *' to 'char *' for 1st argument
extern char *gets (char *__s) __wur __attribute_deprecated__;

तो अब हमें इसके लिए अपेक्षित त्रुटि मिलती है cout << FirstFactorial(gets(stdin));

मैंने एक मैक्रो के लिए जाँच की और #undef getsलगता है कि ऐसा कुछ भी नहीं है, ऐसा लगता है कि यह मैक्रो नहीं है।

परंतु

std::integral_constant<int, gets(stdin)> n;

यह संकलित करता है।

परंतु

std::integral_constant<int, gets(stdin)> n;    // OK
std::integral_constant<int, gets(stdin)> n2;   // ERROR                                          wtf??

n2लाइन पर अपेक्षित त्रुटि के साथ नहीं है ।

और फिर, लगभग किसी भी संशोधन से अपेक्षित त्रुटि के mainलिए लाइन को cout << FirstFactorial(gets(stdin));थूक दिया जाता है।

इसके अलावा stdinवास्तव में खाली लगता है।

इसलिए मैं केवल निष्कर्ष निकाल सकता हूं और अनुमान लगा सकता हूं कि उनके पास एक छोटा सा कार्यक्रम है जो स्रोत को पार्स करता है और gets(stdin)वास्तव में संकलक में खिलाने से पहले परीक्षण केस इनपुट मूल्य से बदलने की कोशिश करता है (खराब) । यदि किसी के पास एक बेहतर सिद्धांत है या वास्तव में जानता है कि वे क्या कर रहे हैं तो कृपया साझा करें!

यह स्पष्ट रूप से एक बहुत बुरा अभ्यास है। इस पर शोध करते समय मैंने पाया कि इस बारे में कम से कम एक प्रश्न ( उदाहरण ) है और क्योंकि लोगों को पता नहीं है कि वहाँ एक साइट है जो ऐसा करता है जो उनका जवाब है "उपयोग न getsकरें ... इसके बजाय" जो वास्तव में है एक अच्छी सलाह है, लेकिन केवल ओपी को अधिक भ्रमित करता है क्योंकि स्टड से एक वैध रीड पर कोई भी प्रयास इस साइट पर विफल हो जाएगा।


TLDR

gets(stdin)अमान्य है C ++। यह एक नौटंकी है जो इस विशेष साइट का उपयोग करती है (किन कारणों से मैं इसका पता नहीं लगा सकता)। यदि आप साइट पर सबमिट करना जारी रखना चाहते हैं (मैं न तो इसका समर्थन कर रहा हूं और न ही इसे एंडोर्स कर रहा हूं) तो आपको इस निर्माण का उपयोग करना होगा, अन्यथा इसका कोई मतलब नहीं होगा, लेकिन ध्यान रखें कि यह भंगुर है। लगभग किसी भी संशोधन में mainएक त्रुटि होगी। इस साइट के बाहर सामान्य इनपुट रीडिंग विधियों का उपयोग किया जाता है।


27
मैं वास्तव में हैरान हूं। शायद यह क्यू / ए एक विहित पोस्ट हो सकता है क्यों न कोडिंग चुनौती साइटों से सीखने के लिए।
igel

28
वास्तव में कुछ बुरा हो रहा है, और मुझे लगता है कि यह संकलक के बाहर स्रोत कोड में पाठ प्रतिस्थापन के स्तर पर है। इसे आज़माएँ: std::cout << "gets(stdin)";और आउटपुट है 8(या जो भी आप 'इनपुट' फ़ील्ड में टाइप करते हैं। यह भाषा का अपमानजनक दुरुपयोग है।
igel

14
@ स्टोबोर ने आसपास के उद्धरणों पर ध्यान दिया "gets(stdin)"। यह एक स्ट्रिंग शाब्दिक है कि प्रीप्रोसेसर भी स्पर्श नहीं करेगा
igel

2
जेम्स किर्क को उद्धृत करने के लिए: "यह बहुत अजीब है।"
ApproachingDarknessFish

2
@alterigel अपने ऊँचे घोड़े से उतरो। यह कोई बयान नहीं है कि कोडिंग चैलेंज साइट्स से सीखना उपयोगी है या नहीं। आप कौन हैं यह तय करने के लिए कि लोग सामान का अभ्यास कैसे करते हैं?
मत्स्येमन

66

मैंने mainकोडरबाइट संपादक में निम्न जोड़ की कोशिश की :

std::cout << "gets(stdin)";

जहां रहस्यमय और गूढ़ स्निपेट gets(stdin)एक स्ट्रिंग शाब्दिक के अंदर दिखाई देता है। यह संभवतः कुछ भी द्वारा रूपांतरित नहीं किया जाना चाहिए, यहां तक ​​कि प्रीप्रोसेसर भी नहीं, और किसी भी C ++ प्रोग्रामर को इस कोड को gets(stdin)मानक आउटपुट के लिए सटीक स्ट्रिंग प्रिंट करने की अपेक्षा करनी चाहिए । और फिर भी हम निम्न आउटपुट देखते हैं, जब कोडरबीट पर संकलित और चलाया जाता है:

8

जहां 8संपादक के अंतर्गत सुविधाजनक 'इनपुट' फ़ील्ड से मान को सीधे लिया जाता है।

जादू कोड

इससे, यह स्पष्ट है कि यह ऑनलाइन संपादक स्रोत कोड पर अंधा खोज और प्रतिस्थापन संचालन कर रहा है, gets(stdin)उपयोगकर्ता के 'इनपुट' के साथ प्रतिस्थापन दिखते हैं । मैं व्यक्तिगत रूप से इस भाषा का दुरुपयोग कहूंगा जो लापरवाह प्रीप्रोसेसर मैक्रोज़ से भी बदतर है।

एक ऑनलाइन कोडिंग चैलेंज वेबसाइट के संदर्भ में, मैं इससे चिंतित हूं क्योंकि यह अपरंपरागत, गैर-मानक, अर्थहीन, और कम से कम असुरक्षित प्रथाओं जैसे gets(stdin)और अन्य प्लेटफार्मों पर दोहराया नहीं जा सकता है।

मुझे यकीन है कि यह नहीं हो सकता हूँ इस बस का उपयोग करने के लिए मुश्किल std::cinएक कार्यक्रम के लिए और सिर्फ धारा इनपुट।


और यह एक अंधा "खोज और प्रतिस्थापित" भी नहीं है क्योंकि कभी-कभी यह इसे बदल देता है कभी-कभी यह नहीं करता है।
बोलाव

4
@bolov क्या यह उस की पहली घटना हो सकती gets(stdin)है? मेरा मतलब इस अर्थ में 'अंधा' था कि यह भाषा के वाक्य-विन्यास या व्याकरण से अनभिज्ञ प्रतीत होता है।
igel

हाँ आप सही है। यह पहली घटना की जगह लेता है। मैंने मुख्य से पहले एक लगाने की कोशिश की और मुझे वास्तव में वही मिला है।
बोवोव

1
आगे के शोध से पता चलता है कि यह साइट सभी भाषाओं के लिए करती है, न केवल C ++ - अजगर / रूबी यह फ़ंक्शन कॉल ("raw_input ()" या "STDIN.gets") का उपयोग करती है, जो आमतौर पर स्टिंग से एक स्ट्रिंग लौटाती है, लेकिन समाप्त कर रही है बदले में उस स्ट्रिंग का स्ट्रिंग प्रतिस्थापन। मुझे लगता है कि गेटलाइन फ़ंक्शन के लिए एक रेगेक्स मैच ढूंढना बहुत कठिन था, इसलिए वे सी / सी ++ के लिए हो जाता है।
स्टोबोर

4
@ मजबूत खतरा, तुम सही हो। मैं पुष्टि कर सकता हूं कि जावा के लिए भी ऐसा होता है, लाइन अपरिभाषित होने पर भी System.out.print(FirstFactorial(s.nextLine()9));प्रिंट करता है। 89s
२०:४१ में igel
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.