আপনি স্ক্যানফ ব্যবহার করে কীভাবে স্পেসগুলি প্রবেশ করতে দেবেন?


129

নিম্নলিখিত কোড ব্যবহার করে:

char *name = malloc(sizeof(char) + 256); 

printf("What is your name? ");
scanf("%s", name);

printf("Hello %s. Nice to meet you.\n", name);

কোনও ব্যবহারকারী তাদের নাম লিখতে পারে তবে তারা যখন কোনও স্থানের মতো কোনও নাম প্রবেশ করায় Lucas Aardvark, scanf()তার পরে সমস্ত কিছু বন্ধ করে দেয় Lucas। আমি কীভাবে scanf()স্পেসগুলিকে অনুমতি দেব


9
নোট করুন যে আরও মূর্তিমানিক হ'ল 'মালোক (আকারের (চর) * 256 + 1)', বা 'ম্যালোক (256 + 1)', বা আরও ভাল ('নাম ধরে নিলে স্থানীয়ভাবে কঠোরভাবে ব্যবহৃত হবে)' চর নাম [256 + 1 ] '। '+1' নাল টার্মিনেটরের জন্য একটি নিমমনিক হিসাবে কাজ করতে পারে, যা বরাদ্দে অন্তর্ভুক্ত করা দরকার।
ব্যারি কেলি

@ ব্যারি - আমার সন্দেহ sizeof(char) + 256ছিল টাইপো ছিল।
ক্রিস লুটজ

উত্তর:


186

লোকেদের (এবং বিশেষত নতুনদের) কখনই scanf("%s")বা gets()অন্য কোনও ফাংশন ব্যবহার করা উচিত নয় বা বাফার ওভারফ্লো সুরক্ষা নেই এমন কোনও ফাংশন ব্যবহার করা উচিত নয় , যদি না আপনি নিশ্চিত হন না যে ইনপুটটি সর্বদা নির্দিষ্ট বিন্যাসে থাকবে (এবং সম্ভবত তখনও নয়)।

scanf"স্ক্যান ফর্ম্যাটেড" এর চেয়ে বেশি মনে রাখবেন এবং ব্যবহারকারীর দ্বারা প্রবেশ করা ডেটার চেয়ে মূল্যবান সামান্য কম ফর্ম্যাট রয়েছে। আপনার যদি ইনপুট ডেটা ফর্ম্যাটটির মোট নিয়ন্ত্রণ থাকে তবে সাধারণত ব্যবহারকারী ইনপুট জন্য অনুপযুক্ত It's

আপনার ইনপুটটিকে স্ট্রিংয়ে আনতে এবং এটি মূল্যায়ন করতে fgets()(যার মধ্যে বাফার ওভারফ্লো সুরক্ষা রয়েছে) ব্যবহার করুন sscanf()। যেহেতু আপনি কেবল বিশ্লেষণ ছাড়াই ব্যবহারকারীর প্রবেশের বিষয়টিটি চান তা এইভাবে আপনার আর দরকার নেই sscanf():

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Maximum name size + 1. */

#define MAX_NAME_SZ 256

int main(int argC, char *argV[]) {
    /* Allocate memory and check if okay. */

    char *name = malloc(MAX_NAME_SZ);
    if (name == NULL) {
        printf("No memory\n");
        return 1;
    }

    /* Ask user for name. */

    printf("What is your name? ");

    /* Get the name, with size limit. */

    fgets(name, MAX_NAME_SZ, stdin);

    /* Remove trailing newline, if there. */

    if ((strlen(name) > 0) && (name[strlen (name) - 1] == '\n'))
        name[strlen (name) - 1] = '\0';

    /* Say hello. */

    printf("Hello %s. Nice to meet you.\n", name);

    /* Free memory and exit. */

    free (name);
    return 0;
}

1
আমি সম্পর্কে জানতাম না fgets()। এটি আসলে ব্যবহার করা সহজ দেখায় scanf()। +1
ক্রেডেন্স

7
আপনি যদি কেবল ব্যবহারকারীর কাছ থেকে একটি লাইন পেতে চান তবে এটি আরও সহজ। আপনি বাফার ওভারফ্লো এড়াতে পারবেন বলে এটিও নিরাপদ। স্ক্যানফ পরিবারটি স্ট্রিংকে বিভিন্ন জিনিসে রূপান্তরিত করার জন্য দরকারী (যেমন চারটি অক্ষর এবং একটি উদাহরণস্বরূপ "% c% c% c% c% d" সহ) তবে, তারপরেও আপনার fgets এবং sscanf ব্যবহার করা উচিত, না স্ক্যানফ, বাফার ওভারফ্লো সম্ভাবনা এড়াতে।
প্যাক্সডিয়াবলো

4
আপনি স্ক্যানফ ফর্ম্যাটে সর্বাধিক বাফার আকার রাখতে পারেন, রানটাইমে বিন্যাসটি তৈরি না করে আপনি রানটাইম গণনা করাতে পারবেন না (প্রিন্টফের জন্য * এর সমতুল্য নেই, * অন্য আচরণের সাথে স্ক্যানফের জন্য বৈধ পরিবর্তনকারী: অ্যাসাইনমেন্ট দমন )।
এপ্রোগ্রামার

নোট যে scanf(যদি সাংখ্যিক রূপান্তর উপচে অনির্ধারিত আচরণ করল N1570 7.21.6.2p10 গত বাক্য, বাক্যে কথন C89 যেহেতু অপরিবর্তিত) যার মানে কেউ এর scanfফাংশন নিরাপদে অবিশ্বস্ত ইনপুটের সাংখ্যিক রূপান্তরের জন্য ব্যবহার করা যাবে।
zwol

@ জোনাথনকুমার এবং ভবিষ্যতে অন্য যে কেউ এটি পড়ছেন: যদি আপনার অধ্যাপক আপনাকে scanfকোনও অ্যাসাইনমেন্টে ব্যবহার করতে বলেছিলেন তবে তারা তা করা ভুল ছিল, এবং আপনি তাদের বলতে পারেন যে আমি এটি বলেছি, এবং তারা যদি আমার সাথে এই বিষয়ে তর্ক করতে চান , আমার ইমেল ঠিকানাটি আমার প্রোফাইল থেকে সহজেই পাওয়া যাবে।
zwol

124

চেষ্টা

char str[11];
scanf("%10[0-9a-zA-Z ]", str);

আশা করি এইটি কাজ করবে.


10
(1) স্পষ্টত স্পেসগুলি গ্রহণ করার জন্য, আপনাকে অক্ষর শ্রেণিতে একটি স্থান রাখা দরকার। (২) নোট করুন যে 10টি হ'ল সর্বাধিক সংখ্যক অক্ষর যা পাঠ করা হবে, তাই স্ট্রিংটি কমপক্ষে 11 আকারের একটি বাফারকে নির্দেশ করতে হবে। (3) এখানে চূড়ান্ত গুলি কোনও ফর্ম্যাট নির্দেশ নয় তবে স্ক্যানফ এটির সাথে মিলিয়ে দেখার জন্য এখানে চেষ্টা করবে। প্রভাবটি 1234567890 এর মতো একটি এন্ট্রিতে দৃশ্যমান হবে যেখানে গুলি ব্যবহার করা হবে তবে কোথায় দেওয়া হবে না। অন্য একটি চিঠি গ্রাস করা হবে না। আপনি যদি এসগুলির পরে অন্য ফর্ম্যাটটি রাখেন তবে এটির সাথে কেবল মিলিত হবে read
এপ্রোগ্রামার

আরেকটি সম্ভাব্য সমস্যা, এর ব্যবহার - প্রথম বা শেষের চেয়ে অন্য জায়গায় বাস্তবায়ন সংজ্ঞায়িত। সাধারণত, এটি ব্যাপ্তিগুলির জন্য ব্যবহৃত হয় তবে পরিসরের নাম নির্ধারিতটি চরসেটের উপর নির্ভর করে। ইবিসিডিআইসির চিঠির পরিসরগুলির মধ্যে ছিদ্র রয়েছে এবং একটি এএসসিআই থেকে প্রাপ্ত চারসেটগুলি ধরে নিলেও এটি ভাবা উচিত যে সমস্ত ছোট অক্ষরের অক্ষর
এজেডের

1
"% [^ \ n]" এর একই সমস্যা যেমন () পায়, বাফার ওভারফ্লো হয়। অতিরিক্ত ক্যাচ দিয়ে \ n ফাইনালটি পড়েনি; এটি এই সত্য দ্বারা গোপন করা হবে যে বেশিরভাগ ফর্ম্যাটগুলি সাদা স্পেস বাদ দিয়ে শুরু করে, তবে [সেগুলির মধ্যে একটিও নয়। স্ট্রিং পড়ার জন্য স্ক্যানফ ব্যবহার করার উদাহরণটি আমি বুঝতে পারি না।
এপ্রোগ্রামার

1
sইনপুট স্ট্রিংয়ের শেষে থেকে এটি সরানো হয়েছে কারণ এটি উভয় ক্ষেত্রেই অতিরিক্ত এবং কিছু ক্ষেত্রে ভুল (পূর্ববর্তী মন্তব্যে উল্লিখিত)। [এটির কিছু পরিবর্তনের চেয়ে এটি নিজস্ব ফর্ম্যাট নির্দিষ্টকরণকারী s
paxdiablo

54

এই উদাহরণটি একটি উল্টানো স্ক্যানসেট ব্যবহার করে, সুতরাং স্ক্যানফ একটি 'line n' - নিউলাইনটির মুখোমুখি না হওয়া অবধি মান গ্রহণ করে চলেছে, তাই স্পেসগুলিও সংরক্ষণ করা যায় until

#include <stdio.h>

int main (int argc, char const *argv[])
{
    char name[20];
    scanf("%[^\n]s",name);
    printf("%s\n", name);
    return 0;
}

1
বাফার ওভারফ্লোসের সাথে যত্নশীল। যদি ব্যবহারকারী 50 টি অক্ষর সহ একটি "নাম" লিখেন, প্রোগ্রামটি সম্ভবত ক্রাশ হবে।
ব্রুনোইস

3
আপনি বাফার আকারটি জানেন, আপনি %20[^\n]sবাফার ওভারফ্লো প্রতিরোধ করতে ব্যবহার করতে পারেন
osvein

45 স্কোর এবং কেউ sসেখানে থাকার সুস্পষ্ট কার্গো সংস্কৃতিকে নির্দেশ করে নি!
অ্যান্টি হাপাল

22

আপনি এটি ব্যবহার করতে পারেন

char name[20];
scanf("%20[^\n]", name);

অথবা এটা

void getText(char *message, char *variable, int size){
    printf("\n %s: ", message);
    fgets(variable, sizeof(char) * size, stdin);
    sscanf(variable, "%[^\n]", variable);
}

char name[20];
getText("Your name", name, 20);

ডেমো


1
আমি পরীক্ষা করিনি, তবে এই একই পৃষ্ঠায় থাকা অন্যান্য উত্তরের ভিত্তিতে, আমি বিশ্বাস করি যে আপনার উদাহরণে স্ক্যানফের জন্য সঠিক বাফার আকারটি হবে: scanf("%19[^\n]", name);(এখনও সংক্ষিপ্ত উত্তরের জন্য +1)
ডঃ বেকো

1
যেমন একটি পার্শ্ব নোট, সর্বদাsizeof(char) সংজ্ঞা অনুসারে 1, সুতরাং এটির দ্বারা গুণ করার দরকার নেই।
প্যাক্সিডিয়াবলো

8

scanf()ক্ষেত্রের প্রস্থ উল্লেখ না করে স্ট্রিং পড়তে ব্যবহার করবেন না । ত্রুটিগুলির জন্য আপনার ফিরে মূল্যগুলিও পরীক্ষা করা উচিত:

#include <stdio.h>

#define NAME_MAX    80
#define NAME_MAX_S "80"

int main(void)
{
    static char name[NAME_MAX + 1]; // + 1 because of null
    if(scanf("%" NAME_MAX_S "[^\n]", name) != 1)
    {
        fputs("io error or premature end of line\n", stderr);
        return 1;
    }

    printf("Hello %s. Nice to meet you.\n", name);
}

বিকল্পভাবে, ব্যবহার করুন fgets():

#include <stdio.h>

#define NAME_MAX 80

int main(void)
{
    static char name[NAME_MAX + 2]; // + 2 because of newline and null
    if(!fgets(name, sizeof(name), stdin))
    {
        fputs("io error\n", stderr);
        return 1;
    }

    // don't print newline
    printf("Hello %.*s. Nice to meet you.\n", strlen(name) - 1, name);
}

6

আপনি fgets()স্ট্রিং পড়তে ফাংশনটি ব্যবহার করতে পারেন বা scanf("%[^\n]s",name);স্ট্রিং রিডিং একটি নতুন লাইন চরিত্রের মুখোমুখি হওয়ার পরে শেষ হবে use


সতর্কতা অবলম্বন করুন যে এটি বাফার ওভারফ্লোগুলি রোধ করতে পারে না
ব্রুনোইস

sসেখানে নেই
আন্তি হাপাল

5

getline()

এখন পসিক্সের অংশ, কোনওটিই কম নয়।

এটি আপনাকে বাফার বরাদ্দের সমস্যাটি সম্পর্কেও যত্ন নিয়েছে যা আপনি আগে জিজ্ঞাসা করেছিলেন, যদিও আপনাকে freeমেমোরিটি আইএনয়ের যত্ন নিতে হবে ।


স্ট্যান্ডার্ড? রেফারেন্সে আপনি উদ্ধৃত করেছেন: "getline () এবং getdelim () উভয়ই GNU এক্সটেনশন s"
এপ্রোগ্রামার

1
POSIX 2008 getline যোগ করে। সুতরাং জিএনইউ এগিয়ে গিয়েছিল এবং ২.৯ সংস্করণে গ্লিবিকের জন্য তাদের শিরোনাম পরিবর্তন করেছে এবং এটি অনেক প্রকল্পের জন্য সমস্যা সৃষ্টি করছে। একটি চূড়ান্ত লিঙ্ক নয়, তবে এখানে দেখুন: bugzilla.redhat.com/show_bug.cgi?id=493941 । অন-লাইন ম্যান পেজ হিসাবে, আমি প্রথম একটি গুগল খুঁজে পেয়েছি।
dmckee --- প্রাক্তন-মডারেটর বিড়ালছানা

3

যদি কেউ এখনও খুঁজছেন তবে আমার জন্য যা কাজ করেছে তা এখানে - স্পেসগুলি সহ স্ট্রিংয়ের একটি স্বেচ্ছাসেবী দৈর্ঘ্য পড়তে।

এই সহজ এবং মার্জিত সমাধান ভাগ করে নেওয়ার জন্য ওয়েবে অনেক পোস্টারকে ধন্যবাদ। এটি যদি কাজ করে তবে ক্রেডিট তাদের কাছে যায় তবে কোনও ত্রুটি আমার।

char *name;
scanf ("%m[^\n]s",&name);
printf ("%s\n",name);

2
এটি লক্ষণীয় যে এটি একটি পসিক্স এক্সটেনশন এবং আইএসও স্ট্যান্ডার্ডে বিদ্যমান নেই। সম্পূর্ণতার জন্য, আপনার সম্ভবত errnoবরাদ্দ মেমরিটিও পরীক্ষা করা এবং পরিষ্কার করা উচিত ।
paxdiablo

sস্ক্যানসেটের পরে সেখানে নেই
অ্যান্টি হাপাল

1

আপনি scanfএই কৌশলটি সামান্য কৌশল দ্বারা ব্যবহার করতে পারেন । প্রকৃতপক্ষে, ব্যবহারকারী প্রবেশ ( \n) এ আঘাত না করা পর্যন্ত আপনার ব্যবহারকারীর ইনপুটটির অনুমতি দেওয়া উচিত । এটি স্থান সহ প্রতিটি চরিত্র বিবেচনা করবে । এখানে উদাহরণ:

int main()
{
  char string[100], c;
  int i;
  printf("Enter the string: ");
  scanf("%s", string);
  i = strlen(string);      // length of user input till first space
  do
  {
    scanf("%c", &c);
    string[i++] = c;       // reading characters after first space (including it)
  } while (c != '\n');     // until user hits Enter
  string[i - 1] = 0;       // string terminating
return 0;
}

এটি কিভাবে কাজ করে? যখন ব্যবহারকারী স্ট্যান্ডার্ড ইনপুট থেকে অক্ষরগুলি ইনপুট করে, তারা প্রথম ফাঁকা স্থান পর্যন্ত স্ট্রিং ভেরিয়েবলে সংরক্ষণ করা হবে। এরপরে, প্রবেশের বিশ্রামটি ইনপুট স্ট্রিমে থাকবে এবং পরবর্তী স্ক্যানফের জন্য অপেক্ষা করবে। এরপরে, আমাদের কাছে একটি forলুপ রয়েছে যা ইনপুট স্ট্রিম থেকে ( \nঅবধি) চর দ্বারা চার গ্রহণ করে এবং স্ট্রিং ভেরিয়েবলের সমাপ্তিতে এটিকে সংযুক্ত করে , এইভাবে কীবোর্ড থেকে ব্যবহারকারী ইনপুট হিসাবে সম্পূর্ণ স্ট্রিং গঠন করে।

আশা করি এটি কারও সাহায্য করবে!


বাফার উপচে পড়ার বিষয়।
paxdiablo

0

যদিও scanf()এই ধরণের জিনিসটির জন্য আপনার সত্যিই ব্যবহার করা উচিত নয় , কারণ আরও অনেক ভাল কল রয়েছে যেমন, gets()বা getline()এটি করা যায়:

#include <stdio.h>

char* scan_line(char* buffer, int buffer_size);

char* scan_line(char* buffer, int buffer_size) {
   char* p = buffer;
   int count = 0;
   do {
       char c;
       scanf("%c", &c); // scan a single character
       // break on end of line, string terminating NUL, or end of file
       if (c == '\r' || c == '\n' || c == 0 || c == EOF) {
           *p = 0;
           break;
       }
       *p++ = c; // add the valid character into the buffer
   } while (count < buffer_size - 1);  // don't overrun the buffer
   // ensure the string is null terminated
   buffer[buffer_size - 1] = 0;
   return buffer;
}

#define MAX_SCAN_LENGTH 1024

int main()
{
   char s[MAX_SCAN_LENGTH];
   printf("Enter a string: ");
   scan_line(s, MAX_SCAN_LENGTH);
   printf("got: \"%s\"\n\n", s);
   return 0;
}

2
মান থেকে অবহেলিত এবং অপসারণ করার একটি কারণ রয়েছেgets ( স্ট্যাকওভারফ্লো.com / প্রশ্নগুলি / 30890696/ why- gets-is-drecated ) from এটি আরও খারাপ যে scanfকারণ অন্ততপক্ষে এটির নিরাপদ করার উপায় রয়েছে।
paxdiablo

-1
/*reading string which contains spaces*/
#include<stdio.h>
int main()
{
   char *c,*p;
   scanf("%[^\n]s",c);
   p=c;                /*since after reading then pointer points to another 
                       location iam using a second pointer to store the base 
                       address*/ 
   printf("%s",p);
   return 0;
 }

4
এটি সঠিক উত্তর কেন আপনি ব্যাখ্যা করতে পারেন? দয়া করে কেবল কোড-উত্তরগুলি পোস্ট করবেন না।
থিও

sস্ক্যানসেটের পরে সেখানে নেই
অ্যান্টি হাপালা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.