সি তে একটি "কলব্যাক" কী এবং সেগুলি কীভাবে বাস্তবায়ন করা হয়?


153

আমি যে পড়াটি করেছি তা থেকে, কোর অডিও কলব্যাকগুলিতে (এবং সি ++, তবে এটি অন্য একটি গল্পের উপর নির্ভর করে) he

আমি একটি ফাংশন স্থাপনের ধারণা (সাজানোর) বুঝতে পারি যা কোনও কার্য সম্পাদন করতে বারবার অন্য একটি ফাংশন দ্বারা ডাকা হয়। আমি ঠিক বুঝতে পারি না যে তারা কীভাবে সেট আপ হয় এবং কীভাবে তারা বাস্তবে কাজ করে। কোন উদাহরণ প্রশংসা করা হবে।

উত্তর:


203

সি তে কোনও "কলব্যাক" নেই - অন্য কোনও জেনেরিক প্রোগ্রামিং ধারণার চেয়ে বেশি নয়।

এগুলি ফাংশন পয়েন্টার ব্যবহার করে প্রয়োগ করা হচ্ছে। এখানে একটি উদাহরণ:

void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
    for (size_t i=0; i<arraySize; i++)
        array[i] = getNextValue();
}

int getNextRandomValue(void)
{
    return rand();
}

int main(void)
{
    int myarray[10];
    populate_array(myarray, 10, getNextRandomValue);
    ...
}

এখানে, populate_arrayফাংশনটি তার তৃতীয় প্যারামিটার হিসাবে একটি ফাংশন পয়েন্টার গ্রহণ করে এবং অ্যারের সাথে মানগুলি তৈরি করার জন্য এটি কল করে। আমরা কলব্যাক লিখেছি getNextRandomValue, যা একটি এলোমেলো-ইশ মান দেয়, এবং এটিতে একটি পয়েন্টার দিয়েছিল populate_arraypopulate_arrayআমাদের কলব্যাক ফাংশনটি 10 ​​বার কল করবে এবং প্রদত্ত অ্যারের উপাদানগুলিতে ফিরে আসা মানগুলি নির্ধারণ করবে।


2
আমি এখানে ভুল হতে পারি, তবে পপুলেট_আরে লাইনে ফাংশন পয়েন্টার হিসাবে থাকা উচিত নয়: অ্যারে [i] = (* getNextValue) (); ?
নাথান ফেলম্যান

40
ঠিকঠাক অপারেটর যেমন ঠিক তেমন ফাংশন পয়েন্টার সহ deচ্ছিক হয়। myfunc (...) = (* myfunc) (...) এবং & myfunc = myfunc
AIB

1
@ নাথানফেলম্যান আমি কেবল বিশেষজ্ঞ সি প্রোগ্রামিং পড়েছি এবং এটি ফাংশন পয়েন্টারটি কলিংয়ের জন্য ভাল ব্যাখ্যা করেছে।
ম্যাট ক্লার্কসন

1
@ জোহনি কারণ মানটি তাই বলে says উর্ধ্বতন মন্তব্য দেখুন।
aib

3
@ পেট্রিক: পপুলেটআরে একটি লাইব্রেরিতে রয়েছে (এবং এটি 12 বছর আগে লেখা হয়েছিল) এবং আপনি getNextRandomValue নিজে লিখেছেন (গতকাল); সুতরাং এটি সরাসরি কল করতে পারে না। আপনি কোনও তুলনাকারী নিজেকে সরবরাহ করে এমন একটি লাইব্রেরি সাজানোর ক্রিয়াটি ভাবেন।
আইবি

121

এখানে সি-তে কলব্যাকের উদাহরণ রয়েছে

ধরা যাক আপনি এমন কিছু কোড লিখতে চান যা কোনও ইভেন্ট ঘটলে কলব্যাকগুলি কল করার জন্য কল করতে পারে register

প্রথমে কলব্যাকের জন্য ব্যবহৃত ফাংশনের ধরণটি সংজ্ঞায়িত করুন:

typedef void (*event_cb_t)(const struct event *evt, void *userdata);

এখন, একটি ফাংশন সংজ্ঞায়িত করুন যা কলব্যাক রেজিস্টার করতে ব্যবহৃত হয়:

int event_cb_register(event_cb_t cb, void *userdata);

কোডটি কলব্যাকটিকে নিবন্ধভুক্ত করার মতো দেখতে এই জাতীয় কোডটি দেখাবে:

static void my_event_cb(const struct event *evt, void *data)
{
    /* do stuff and things with the event */
}

...
   event_cb_register(my_event_cb, &my_custom_data);
...

ইভেন্ট প্রেরণের অভ্যন্তরগুলিতে, কলব্যাকটি এমন স্ট্রাক্টে সংরক্ষণ করা যেতে পারে যা দেখতে এর মতো কিছু দেখায়:

struct event_cb {
    event_cb_t cb;
    void *data;
};

কোডটি কলব্যাক কার্যকর করে এমনটাই দেখায়।

struct event_cb *callback;

...

/* Get the event_cb that you want to execute */

callback->cb(event, callback->data);

ঠিক যেটা আমার দরকার ছিল. আপনার ব্যবহারকারীরা যদি কলব্যাক ফাংশনে প্রয়োজনীয় কাস্টম ডেটা (যেমন ডিভাইস হ্যান্ডলগুলি) পাস করতে চান তবে ইউজারডাটা অংশটি খুব সহায়ক।
uceumern

যাচাই প্রশ্ন: ফাংশন ঠিকানার পয়েন্টার হওয়ার কারণে কি একটি তারকাচিহ্নযুক্ত কলব্যাক টাইপডেফ? যদি তারকাচিহ্নটি অনুপস্থিত থাকে তবে তা কী ভুল হবে? যদি এটি ভুল হয় তবে গিথুব-এ সিসকো লাইব্রের্প লাইব্রেরিতে দুটি নিখোঁজ তারা রয়েছে: github.com/cisco/libsrtp/blob/… github.com/cisco/libsrtp/blob/…
twildeman

@twildeman সতর্কতা সহ একটি স্ট্যান্ডার্ড সি মোডে সংকলন করে আপনার নিজের প্রশ্নের উত্তর দেওয়া তুচ্ছ বলে মনে হচ্ছে। আপনি একটি ন্যূনতম পরীক্ষা প্রোগ্রামও লিখতে পারেন। কোডগুলি যেমন libsrtpকোনও সতর্কতা দেয় না। তখন আমি অনুমান করি যে যখন এই জাতীয় ধরণটি একটি ফাংশন আর্গুমেন্ট হিসাবে উপস্থিত হয়, তখন এটি পয়েন্টার-টু-ফাংশনে 'ক্ষয়' হওয়া দরকার, ঠিক যেমন অ্যারেগুলি তাদের প্রথম উপাদানগুলিতে পয়েন্টারকে ক্ষয় করতে থাকে, তাই একই জিনিসটি শেষ পর্যন্ত ঘটে যেভাবেই হোক এটা তোলে হয় , আকর্ষণীয় যদিও, আমি পেয়েছি যেমন typedefs আলোচনার এই দৃষ্টিভঙ্গি এ এমনকি নজরে না বরং এগুলির নমুনা বা এটির সাথে পয়েন্টার প্রকাশক দিকে নজর দিন
underscore_d

এটি কী করে আমার কোনও ধারণা নেই এবং এটি সফলভাবে সংকলন করতে অক্ষম। সফলভাবে সংকলনের জন্য কেউ কি বিশদভাবে এটি ব্যাখ্যা করতে পারেন বা বাকী কোডটি পূরণ করতে পারেন?
অ্যান্ডি লিন

20

একটি সাধারণ কল ব্যাক প্রোগ্রাম। আশা করি এটি আপনার প্রশ্নের উত্তর দিয়েছে।

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include "../../common_typedef.h"

typedef void (*call_back) (S32, S32);

void test_call_back(S32 a, S32 b)
{
    printf("In call back function, a:%d \t b:%d \n", a, b);
}

void call_callback_func(call_back back)
{
    S32 a = 5;
    S32 b = 7;

    back(a, b);
}

S32 main(S32 argc, S8 *argv[])
{
    S32 ret = SUCCESS;

    call_back back;

    back = test_call_back;

    call_callback_func(back);

    return ret;
}

9

সিতে একটি কলব্যাক ফাংশন অন্য ফাংশনের মধ্যে ব্যবহারের জন্য নির্ধারিত কোনও ফাংশন প্যারামিটার / ভেরিয়েবলের সমতুল্য। উইকি উদাহরণ

নীচের কোডে,

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

/* The calling function takes a single callback as a parameter. */
void PrintTwoNumbers(int (*numberSource)(void)) {
    printf("%d and %d\n", numberSource(), numberSource());
}

/* A possible callback */
int overNineThousand(void) {
    return (rand() % 1000) + 9001;
}

/* Another possible callback. */
int meaningOfLife(void) {
    return 42;
}

/* Here we call PrintTwoNumbers() with three different callbacks. */
int main(void) {
    PrintTwoNumbers(&rand);
    PrintTwoNumbers(&overNineThousand);
    PrintTwoNumbers(&meaningOfLife);
    return 0;
}

PrintTwoNumbers ফাংশন কলটির ভিতরে ফাংশন (* সংখ্যাসোর্স) হ'ল কোড দ্বারা চালিত কোড অনুসারে প্রিন্ট টু নাম্বারগুলি থেকে "কল ব্যাক" / এক্সিকিউট করা একটি ফাংশন।

সুতরাং আপনার যদি পাইথ্রেড ফাংশনের মতো কিছু থাকে তবে আপনি এটির ইনস্ট্যান্টেশন থেকে লুপের অভ্যন্তরে চালানোর জন্য আরও একটি ফাংশন নির্ধারণ করতে পারেন।


6

সি-তে একটি কলব্যাক এমন একটি ফাংশন যা অন্য ফাংশনটি যখন অন্য ফাংশনটি তার কাজটি সম্পাদন করে তখন এক পর্যায়ে "কল টু ব্যাক" সরবরাহ করা হয়।

আছে দুটি উপায়ে যে একটি কলব্যাক ব্যবহৃত হয় সমকালীন কলব্যাক এবং অ্যাসিঙ্ক্রোনাস কলব্যাক। একটি সিঙ্ক্রোনাস কলব্যাক অন্য ফাংশনে সরবরাহ করা হয় যা কিছু কাজ করতে চলেছে এবং তারপরে টাস্কটি সম্পন্ন করে কলারে ফিরে আসবে। একটি অ্যাসিঙ্ক্রোনাস কলব্যাক অন্য ফাংশনে সরবরাহ করা হয় যা কোনও কাজ শুরু করতে চলেছে এবং তারপরে কলিংয়ের কাছে ফিরে আসা কার্যটি সম্পন্ন না করে।

একটি সিঙ্ক্রোনাস কলব্যাক সাধারণত অন্য ফাংশনে একটি প্রতিনিধি সরবরাহ করতে ব্যবহৃত হয় যেখানে অন্য ফাংশনটি কাজের কিছু ধাপকে প্রতিনিধিত্ব করে। এই প্রতিনিধিদলের ক্লাসিক উদাহরণ ফাংশন হয় bsearch()এবং qsort()সি স্ট্যান্ডার্ড লাইব্রেরী থেকে। এই উভয় ফাংশনই একটি কলব্যাক নেয় যা ফাংশনটি প্রদান করা টাস্ক চলাকালীন ব্যবহৃত হয় যাতে ডাটা যে ধরণের অনুসন্ধান করা হচ্ছে তার ক্ষেত্রে bsearch()বা সাজানোর ক্ষেত্রে qsort()ফাংশনটির দ্বারা তা জানা প্রয়োজন হবে না ব্যবহার করা হয়েছে।

উদাহরণস্বরূপ, এখানে bsearch()বিভিন্ন তুলনা ফাংশন, সিঙ্ক্রোনাস কলব্যাক্স সহ একটি ছোট নমুনা প্রোগ্রাম । কলব্যাক ফাংশনটির সাথে আমাদের তুলনা করে ডেটা অর্পণ করার অনুমতি দিয়ে, bsearch()ফাংশনটি আমাদের কোন ধরণের তুলনা ব্যবহার করতে চাই তা রান সময়ে সিদ্ধান্ত নিতে দেয়। এটি সিঙ্ক্রোনাস কারণ bsearch()ফাংশনটি যখন ফিরিয়ে দেয় তখন টাস্কটি সম্পূর্ণ হয়।

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

typedef struct {
    int iValue;
    int kValue;
    char label[6];
} MyData;

int cmpMyData_iValue (MyData *item1, MyData *item2)
{
    if (item1->iValue < item2->iValue) return -1;
    if (item1->iValue > item2->iValue) return 1;
    return 0;
}

int cmpMyData_kValue (MyData *item1, MyData *item2)
{
    if (item1->kValue < item2->kValue) return -1;
    if (item1->kValue > item2->kValue) return 1;
    return 0;
}

int cmpMyData_label (MyData *item1, MyData *item2)
{
    return strcmp (item1->label, item2->label);
}

void bsearch_results (MyData *srch, MyData *found)
{
        if (found) {
            printf ("found - iValue = %d, kValue = %d, label = %s\n", found->iValue, found->kValue, found->label);
        } else {
            printf ("item not found, iValue = %d, kValue = %d, label = %s\n", srch->iValue, srch->kValue, srch->label);
        }
}

int main ()
{
    MyData dataList[256] = {0};

    {
        int i;
        for (i = 0; i < 20; i++) {
            dataList[i].iValue = i + 100;
            dataList[i].kValue = i + 1000;
            sprintf (dataList[i].label, "%2.2d", i + 10);
        }
    }

//  ... some code then we do a search
    {
        MyData srchItem = { 105, 1018, "13"};
        MyData *foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_iValue );

        bsearch_results (&srchItem, foundItem);

        foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_kValue );
        bsearch_results (&srchItem, foundItem);

        foundItem = bsearch (&srchItem, dataList, 20, sizeof(MyData), cmpMyData_label );
        bsearch_results (&srchItem, foundItem);
    }
}

একটি অ্যাসিঙ্ক্রোনাস কলব্যাক এর মধ্যে আলাদা হয় যখন কল কলটি আমরা কলব্যাক রিটার্ন সরবরাহ করি তখন টাস্কটি সম্পন্ন নাও হতে পারে। এই ধরণের কলব্যাক প্রায়শই অ্যাসিনক্রোনাস আই / ও এর সাথে ব্যবহৃত হয় যার মধ্যে একটি আই / ও ক্রিয়াকলাপ শুরু হয় এবং তারপরে এটি শেষ হয়ে গেলে কলব্যাকটি চাওয়া হয়।

নিম্নলিখিত প্রোগ্রামে আমরা টিসিপি সংযোগের অনুরোধগুলির জন্য শোনার জন্য একটি সকেট তৈরি করি এবং যখন কোনও অনুরোধ পাওয়া যায়, শ্রবণটি করে ফাংশনটি প্রদত্ত কলব্যাক ফাংশনটি আহ্বান করে। এই সাধারণ অ্যাপ্লিকেশনটি telnetঅন্য উইন্ডোতে সংযোগ স্থাপনের চেষ্টা করতে ইউটিলিটি বা ওয়েব ব্রাউজার ব্যবহার করার সময় এটি একটি উইন্ডোতে চালিত করে ব্যবহার করা যেতে পারে ।

মাইক্রোসফ্ট https://msdn.microsoft.com/en-us/library/windows/desktop/ms737526(vvv..85).aspxaccept() এ মাইক্রোসফ্ট ফাংশনটি সরবরাহ করে তার উদাহরণ থেকে আমি বেশিরভাগ উইনসক কোডটি তুলেছি

এই অ্যাপ্লিকেশনটি listen()স্থানীয় হোস্টে, 127.0.0.1 থেকে একটি পোর্ট 8282 ব্যবহার করে আরম্ভ করবে যাতে আপনি হয় telnet 127.0.0.1 8282বা ব্যবহার করতে পারেন http://127.0.0.1:8282/

এই নমুনা অ্যাপ্লিকেশনটি ভিজ্যুয়াল স্টুডিও 2017 সম্প্রদায়ের সংস্করণ সহ একটি কনসোল অ্যাপ্লিকেশন হিসাবে তৈরি করা হয়েছিল এবং এটি সকেটের মাইক্রোসফ্ট উইনসক সংস্করণ ব্যবহার করছে। একটি লিনাক্স অ্যাপ্লিকেশনের জন্য উইনসক ফাংশনগুলি লিনাক্স বিকল্পগুলির সাথে প্রতিস্থাপন করা প্রয়োজন এবং উইন্ডোজ থ্রেড লাইব্রেরির pthreadsপরিবর্তে ব্যবহার করা হবে।

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

#include <Windows.h>

// Need to link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

// function for the thread we are going to start up with _beginthreadex().
// this function/thread will create a listen server waiting for a TCP
// connection request to come into the designated port.
// _stdcall modifier required by _beginthreadex().
int _stdcall ioThread(void (*pOutput)())
{
    //----------------------
    // Initialize Winsock.
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        printf("WSAStartup failed with error: %ld\n", iResult);
        return 1;
    }
    //----------------------
    // Create a SOCKET for listening for
    // incoming connection requests.
    SOCKET ListenSocket;
    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {
        wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //----------------------
    // The sockaddr_in structure specifies the address family,
    // IP address, and port for the socket that is being bound.
    struct sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_addr.s_addr = inet_addr("127.0.0.1");
    service.sin_port = htons(8282);

    if (bind(ListenSocket, (SOCKADDR *)& service, sizeof(service)) == SOCKET_ERROR) {
        printf("bind failed with error: %ld\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    //----------------------
    // Listen for incoming connection requests.
    // on the created socket
    if (listen(ListenSocket, 1) == SOCKET_ERROR) {
        printf("listen failed with error: %ld\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    //----------------------
    // Create a SOCKET for accepting incoming requests.
    SOCKET AcceptSocket;
    printf("Waiting for client to connect...\n");

    //----------------------
    // Accept the connection.
    AcceptSocket = accept(ListenSocket, NULL, NULL);
    if (AcceptSocket == INVALID_SOCKET) {
        printf("accept failed with error: %ld\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    else
        pOutput ();   // we have a connection request so do the callback

    // No longer need server socket
    closesocket(ListenSocket);

    WSACleanup();
    return 0;
}

// our callback which is invoked whenever a connection is made.
void printOut(void)
{
    printf("connection received.\n");
}

#include <process.h>

int main()
{
     // start up our listen server and provide a callback
    _beginthreadex(NULL, 0, ioThread, printOut, 0, NULL);
    // do other things while waiting for a connection. In this case
    // just sleep for a while.
    Sleep(30000);
}

উভয় সিঙ্ক্রোনাস এবং অ্যাসিনক্রোনাস কল-ব্যাক প্রদর্শন করে দুর্দান্ত উত্তর। সি- * এনআইএক্স-এ অ্যাসিক্রোনাস কল-ব্যাকের ব্যবহারের আরেকটি সুনির্দিষ্ট উদাহরণ হ'ল অ্যাসিনক্রোনাস সিগন্যাল এবং তাদের সংকেত হ্যান্ডলার। এখানে লিনাক্স [লিংক] ( স্ট্যাকওভারফ্লো / প্রশ্ন / 4৯৪৯০২৫/২ ) সিগন্যাল হ্যান্ডলারগুলি কীভাবে প্রক্রিয়াজাত হয় তার একটি দুর্দান্ত বর্ণনা এখানে দেওয়া হয়েছে ।
ড্রিলি

4

সি-তে কলব্যাকগুলি সাধারণত ফাংশন পয়েন্টার এবং একটি সম্পর্কিত ডেটার পয়েন্টার ব্যবহার করে প্রয়োগ করা হয়। আপনি আপনার ফাংশন on_event()এবং ডেটা পয়েন্টারগুলিকে কোনও ফ্রেমওয়ার্ক ফাংশনে watch_events()(উদাহরণস্বরূপ) পাস করেন। যখন কোনও ইভেন্ট ঘটে তখন আপনার ফাংশনটি আপনার ডেটা এবং কিছু ইভেন্ট-নির্দিষ্ট ডেটা দিয়ে ডাকা হয়।

জিবিআই প্রোগ্রামিংয়ে কলব্যাকগুলিও ব্যবহৃত হয়। জিটিকে + টিউটোরিয়াল উপর একটা চমৎকার অধ্যায় আছে সিগন্যাল ও callbacks তত্ত্ব


2

এই উইকিপিডিয়া নিবন্ধটি সিতে একটি উদাহরণ রয়েছে

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


0

সাধারণত এটি একটি ফাংশন পয়েন্টার ব্যবহার করে করা যায়, এটি একটি বিশেষ ভেরিয়েবল যা কোনও ফাংশনের মেমরির অবস্থানকে নির্দেশ করে। তারপরে আপনি নির্দিষ্ট যুক্তি সহ ফাংশনটি কল করতে এটি ব্যবহার করতে পারেন। সুতরাং সম্ভবত একটি ফাংশন হবে যা কলব্যাক ফাংশন সেট করে। এটি কোনও ফাংশন পয়েন্টার গ্রহণ করবে এবং তারপরে যেখানে ঠিকানাটি ব্যবহার করা যেতে পারে সেখানে সংরক্ষণ করবে। এর পরে যখন নির্দিষ্ট ইভেন্টটি ট্রিগার করা হয়, তখন এটি সেই ফাংশনটিকে কল করবে।


0

উদাহরণের মাধ্যমে একটি ধারণা বোঝা অনেক সহজ। সিতে এখন পর্যন্ত কলব্যাক ফাংশন সম্পর্কে যা বলা হয়েছিল তা হ'ল দুর্দান্ত উত্তর, তবে সম্ভবত বৈশিষ্ট্যটি ব্যবহারের সবচেয়ে বড় সুবিধা হ'ল কোডটি পরিষ্কার এবং নিরবচ্ছিন্নভাবে রাখা।

উদাহরণ

নিম্নলিখিত সি কোড দ্রুত বাছাই কার্যকর করে। নীচের কোডটির মধ্যে সবচেয়ে আকর্ষণীয় লাইনটি হ'ল এটি, যেখানে আমরা কলব্যাক ফাংশনটি কার্যত দেখতে পাচ্ছি:

qsort(arr,N,sizeof(int),compare_s2b);

তুলনা_স 2 বি ফাংশনের নাম যা qsort () ফাংশনটি কল করতে ব্যবহার করছে। এটি কিউসোর্টকে () এতটাই নিরস্ত্র করে রাখে (তাই বজায় রাখা সহজ)। আপনি কেবলমাত্র অন্য ফাংশনের অভ্যন্তর থেকে নাম ধরে কোনও ফাংশনটি কল করবেন (অবশ্যই, ফাংশন প্রোটোটাইপ ঘোষণা, কমপক্ষে, অন্য কোনও ফাংশন থেকে ডেকে আনার আগে অবশ্যই পূর্বসূচি করতে হবে)।

সম্পূর্ণ কোড

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

int arr[]={56,90,45,1234,12,3,7,18};
//function prototype declaration 

int compare_s2b(const void *a,const void *b);

int compare_b2s(const void *a,const void *b);

//arranges the array number from the smallest to the biggest
int compare_s2b(const void* a, const void* b)
{
    const int* p=(const int*)a;
    const int* q=(const int*)b;

    return *p-*q;
}

//arranges the array number from the biggest to the smallest
int compare_b2s(const void* a, const void* b)
{
    const int* p=(const int*)a;
    const int* q=(const int*)b;

    return *q-*p;
}

int main()
{
    printf("Before sorting\n\n");

    int N=sizeof(arr)/sizeof(int);

    for(int i=0;i<N;i++)
    {
        printf("%d\t",arr[i]);
    }

    printf("\n");

    qsort(arr,N,sizeof(int),compare_s2b);

    printf("\nSorted small to big\n\n");

    for(int j=0;j<N;j++)
    {
        printf("%d\t",arr[j]);
    }

    qsort(arr,N,sizeof(int),compare_b2s);

    printf("\nSorted big to small\n\n");

    for(int j=0;j<N;j++)
    {
        printf("%d\t",arr[j]);
    }

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