سؤال

ما هي أبسط طريقة لقراءة سطر كامل في برنامج Console C قد يكون للنص الذي تم إدخاله طولًا متغيرًا ولا يمكننا وضع أي افتراض حول محتواه.

هل كانت مفيدة؟

المحلول

وتحتاج إدارة الذاكرة الديناميكية، واستخدام وظيفة fgets لقراءة الخط الخاص بك. ومع ذلك، يبدو أن هناك أي وسيلة لمعرفة عدد الأحرف قراءتها. لذلك يمكنك استخدام fgetc:

char * getline(void) {
    char * line = malloc(100), * linep = line;
    size_t lenmax = 100, len = lenmax;
    int c;

    if(line == NULL)
        return NULL;

    for(;;) {
        c = fgetc(stdin);
        if(c == EOF)
            break;

        if(--len == 0) {
            len = lenmax;
            char * linen = realloc(linep, lenmax *= 2);

            if(linen == NULL) {
                free(linep);
                return NULL;
            }
            line = linen + (line - linep);
            linep = linen;
        }

        if((*line++ = c) == '\n')
            break;
    }
    *line = '\0';
    return linep;
}

ملاحظة : لعدم استخدام يحصل! وهي لا تفعل حدود فحص ويمكن تجاوز سعة المخزن المؤقت الخاص بك

نصائح أخرى

إذا كنت تستخدم مكتبة GNU C أو مكتبة أخرى، POSIX متوافقة، يمكنك استخدام <لأ href = "http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html" يختلط = "noreferrer "> getline() و تمرير stdin إليها لتيار الملف.

ووتنفيذ بسيط جدا ولكن غير آمنة لقراءة خط لتخصيص ثابت:

char line[1024];

scanf("%[^\n]", line);

ووتنفيذ أكثر أمانا، من دون إمكانية تجاوز سعة المخزن المؤقت، ولكن مع احتمال عدم قراءة الخط كله، هو:

char line[1024];

scanf("%1023[^\n]", line);

وليس "الاختلاف من جانب واحد" بين طول المحدد إعلان متغير وطول المحدد في سلسلة تنسيق. ومن الحرفية التاريخية.

وقد تحتاج إلى استخدام حرف بحرف (getc ()) حلقة لضمان لم يكن لديك عازلة الفيضانات ولا اقتطاع الإدخال.

لذا، إذا كنت تبحث عن وسيطات الأمر، فألق نظرة على إجابة تيم.إذا كنت تريد فقط قراءة سطر من وحدة التحكم:

#include <stdio.h>

int main()
{
  char string [256];
  printf ("Insert your full address: ");
  gets (string);
  printf ("Your address is: %s\n",string);
  return 0;
}

نعم، إنه غير آمن، يمكنك تجاوز المخزن المؤقت، ولا يتحقق من نهاية الملف، ولا يدعم الترميزات والكثير من الأشياء الأخرى.في الواقع لم أفكر حتى فيما إذا كان قد فعل أيًا من هذه الأشياء.أوافق على أنني ثمل كيندا :) لكن... عندما أرى سؤالا مثل "كيفية قراءة سطر من وحدة التحكم في C؟" ، أفترض أن الشخص يحتاج إلى شيء بسيط ، مثل gets () وليس 100 سطر من التعليمات البرمجية كما هو مذكور أعلاه.في الواقع، أعتقد أنك إذا حاولت كتابة 100 سطر من التعليمات البرمجية في الواقع، فسوف ترتكب عددًا من الأخطاء أكثر مما كنت ستفعله لو اخترت get ;)

getline مثال قابل للتشغيل

مذكور على هذه الإجابة ولكن هنا مثال.

إنها بوسيكس 7, ، يخصص لنا الذاكرة، ويعيد استخدام المخزن المؤقت المخصص في حلقة بشكل جيد.

مؤشر نيوبس، اقرأ هذا: لماذا تعتبر الوسيطة الأولى لخط getline مؤشرًا للمؤشر "char**" بدلاً من "char*"؟

#define _XOPEN_SOURCE 700

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

int main(void) {
    char *line = NULL;
    size_t len = 0;
    ssize_t read = 0;
    while (read != -1) {
        puts("enter a line");
        read = getline(&line, &len, stdin);
        printf("line = %s", line);
        printf("line length = %zu\n", read);
        puts("");
    }
    free(line);
    return 0;
}

تنفيذ glibc

لا بوسيكس؟ربما تريد أن تنظر إلى تطبيق glibc 2.23.

يقرر أن getdelim, ، وهي مجموعة شاملة بسيطة من POSIX getline مع فاصل خط تعسفي.

فهو يضاعف الذاكرة المخصصة كلما كانت هناك حاجة إلى زيادتها، ويبدو آمنًا.

يتطلب الأمر بعض التوسع الكلي، ولكن من غير المرجح أن تفعل ما هو أفضل بكثير.

وكما اقترح، يمكنك استخدام getchar () لقراءة من وحدة التحكم حتى في نهاية خط أو إرجاع EOF، بناء عازلة الخاص بك. عازلة المتزايد يمكن أن يحدث بشكل حيوي إذا كنت غير قادر على تعيين الحد الأقصى لحجم خط معقول.

ويمكنك استخدام أيضا استخدام fgets كوسيلة آمنة للحصول على خط كسلسلة خالية منتهية C:

#include <stdio.h>

char line[1024];  /* Generously large value for most situations */

char *eof;

line[0] = '\0'; /* Ensure empty line if no input delivered */
line[sizeof(line)-1] = ~'\0';  /* Ensure no false-null at end of buffer */

eof = fgets(line, sizeof(line), stdin);

إذا كنت قد استنفدت حدة الإدخال أو إذا فشلت العملية لسبب ما، يتم إرجاع الفولكلوري == NULL وعازلة خط قد يكون دون تغيير (وهذا هو السبب وضع الحرف الأول لل'\ 0' هو مفيد).

وسوف fgets لا يفيض خط [] وسيضمن أن هناك لاغية بعد الحرف الأخير قبلت على عودة ناجحة.

إذا تم التوصل إلى نهاية الخط، الحرف الذي يسبق تنتهي '\ 0' ستكون '\ ن'.

إذا لم يكن هناك تنتهي '\ ن' قبل إنهاء '\ 0' قد يكون أن هناك المزيد من البيانات أو أن الطلب القادم سوف يقدم تقريرا في نهاية الملف. سيكون لديك لتفعل fgets أخرى لتحديد ما هو الذي. (وفي هذا الصدد، حلقات مع getchar () هو أسهل).

في ل(تحديث) رمز المثال أعلاه، إذا خط [sizeof (خط) -1] == '\ 0' بعد fgets ناجحة، وانت تعرف أن المخزن المؤقت امتلأت تماما. وإذا شرع هذا الموقف من قبل '\ ن' كما تعلمون كنت محظوظا. خلاف ذلك، هناك إما المزيد من البيانات أو نهاية الملف حتى قدما في ستدين. (عندما لا شغل في المخزن المؤقت تماما، هل يمكن أن يكون لا يزال في وضع نهاية لملف وأيضا قد لا يكون هناك '\ ن' في نهاية السطر الحالي. منذ لديك لمسح سلسلة لإيجاد و/ أو القضاء على أي '\ ن' قبل نهاية السلسلة (أول '\ 0' في المخزن المؤقت)، وأنا أميل إلى تفضيل استخدام getchar () في المقام الأول).

هل ما عليك القيام به للتعامل مع وجود لا يزال يجري المزيد من خط من المبلغ الذي يصبح نصها كما أول قطعة. ويمكن إجراء الأمثلة على النمو بشكل ديناميكي عازلة للعمل مع أي getchar أو fgets. هناك بعض الحالات حافة صعبة لمشاهدة ل(مثل تذكر في الحصول على مدخلات المقبل تبدأ تخزين في موقف '\ 0' التي أنهت الإدخال السابق قبل مددت المخزن المؤقت).

كثير من الناس، مثلي، يأتون إلى هذا المنشور بعنوان يطابق ما يتم البحث عنه، على الرغم من أن الوصف يتحدث عن طول متغير.في معظم الحالات، نعرف الطول مسبقًا.

إذا كنت تعرف الطول قبل اليد، فجرّب ما يلي:

char str1[1001] = { 0 };
fgets(str1, 1001, stdin); // 1000 chars may be read

مصدر: https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm

كيفية قراءة سطر من وحدة التحكم في لغة C؟

  • بناء وظيفتك الخاصة, ، هي إحدى الطرق التي من شأنها أن تساعدك على تحقيق قراءة سطر من وحدة التحكم في ج.

  • أنا استخدم تخصيص الذاكرة الديناميكية لتخصيص المقدار الكافي من الذاكرة المطلوبة لاستيعاب كافة أحرف السطر جنبًا إلى جنب مع '\0' شخصية.

  • وأنا هنا أستخدم حلقة لمسح كل حرف من السلسلة واحدًا تلو الآخر باستخدام ملف getchar() وظيفة حتى يدخل المستخدم '\n' أو EOF شخصية

    //the function to read lines of variable length
    
    char* scan_line(char *line)
    {
        int ch; //as getchar() returns `int`
    
        if( (line = malloc(sizeof(char))) == NULL) //allocating memory
        {
            //checking if allocation was successful or not
            printf("unsuccessful allocation");
            exit(1);
        }
    
        line[0]='\0';
    
        for(int index = 0; ( (ch = getchar())!='\n' ) && (ch != EOF) ; index++)
        {
            if( (line = realloc(line, (index + 2)*sizeof(char))) == NULL )
            {
                //checking if reallocation was successful or not
                printf("unsuccessful reallocation");
                exit(1);
            }
    
            line[index] = (char) ch; //type casting `int` to `char`
            line[index + 1] = '\0'; //inserting null character at the end
        }
    
        return line;
    }  
    
  • الآن يمكنك قراءة سطر كامل بهذه الطريقة:

    char *line = NULL;
    line = scan_line(line);
    

هنا برنامج المثال باستخدام scan_line() وظيفة :

#include <stdio.h>
#include <stdlib.h> //for dynamic allocation functions

char* scan_line(char *line)
{
    ..........
}

int main(void)
{
    char *a = NULL;

    a = scan_line(a); //function call to scan the line

    printf("%s\n",a); //printing the scanned line

    free(a); //don't forget to free the malloc'd pointer
}

إدخال العينة :

Twinkle Twinkle little star.... in the sky!

إخراج العينة :

Twinkle Twinkle little star.... in the sky!

وجئت عبر نفس المشكلة منذ بعض الوقت، وكان هذا حل بي، ونأمل أن يساعد.

/*
 * Initial size of the read buffer
 */
#define DEFAULT_BUFFER 1024

/*
 * Standard boolean type definition
 */
typedef enum{ false = 0, true = 1 }bool;

/*
 * Flags errors in pointer returning functions
 */
bool has_err = false;

/*
 * Reads the next line of text from file and returns it.
 * The line must be free()d afterwards.
 *
 * This function will segfault on binary data.
 */
char *readLine(FILE *file){
    char *buffer   = NULL;
    char *tmp_buf  = NULL;
    bool line_read = false;
    int  iteration = 0;
    int  offset    = 0;

    if(file == NULL){
        fprintf(stderr, "readLine: NULL file pointer passed!\n");
        has_err = true;

        return NULL;
    }

    while(!line_read){
        if((tmp_buf = malloc(DEFAULT_BUFFER)) == NULL){
            fprintf(stderr, "readLine: Unable to allocate temporary buffer!\n");
            if(buffer != NULL)
                free(buffer);
            has_err = true;

            return NULL;
        }

        if(fgets(tmp_buf, DEFAULT_BUFFER, file) == NULL){
            free(tmp_buf);

            break;
        }

        if(tmp_buf[strlen(tmp_buf) - 1] == '\n') /* we have an end of line */
            line_read = true;

        offset = DEFAULT_BUFFER * (iteration + 1);

        if((buffer = realloc(buffer, offset)) == NULL){
            fprintf(stderr, "readLine: Unable to reallocate buffer!\n");
            free(tmp_buf);
            has_err = true;

            return NULL;
        }

        offset = DEFAULT_BUFFER * iteration - iteration;

        if(memcpy(buffer + offset, tmp_buf, DEFAULT_BUFFER) == NULL){
            fprintf(stderr, "readLine: Cannot copy to buffer\n");
            free(tmp_buf);
            if(buffer != NULL)
                free(buffer);
            has_err = true;

            return NULL;
        }

        free(tmp_buf);
        iteration++;
    }

    return buffer;
}

في أنظمة BSD والروبوت يمكنك أيضا استخدام fgetln:

#include <stdio.h>

char *
fgetln(FILE *stream, size_t *len);

ومثل ذلك:

size_t line_len;
const char *line = fgetln(stdin, &line_len);

وليس فارغة إنهاء line ويحتوي \n (أو كل ما هو النظام الأساسي الخاص بك يستخدم) في نهاية المطاف. يصبح غير صالح بعد العملية المقبلة I / O على تيار.

وشيء من هذا القبيل:

unsigned int getConsoleInput(char **pStrBfr) //pass in pointer to char pointer, returns size of buffer
{
    char * strbfr;
    int c;
    unsigned int i;
    i = 0;
    strbfr = (char*)malloc(sizeof(char));
    if(strbfr==NULL) goto error;
    while( (c = getchar()) != '\n' && c != EOF )
    {
        strbfr[i] = (char)c;
        i++;
        strbfr = (void*)realloc((void*)strbfr,sizeof(char)*(i+1));
        //on realloc error, NULL is returned but original buffer is unchanged
        //NOTE: the buffer WILL NOT be NULL terminated since last
        //chracter came from console
        if(strbfr==NULL) goto error;
    }
    strbfr[i] = '\0';
    *pStrBfr = strbfr; //successfully returns pointer to NULL terminated buffer
    return i + 1; 
    error:
    *pStrBfr = strbfr;
    return i + 1;
}

وهذه الوظيفة يجب أن تفعل ما تريد:

char* readLine( FILE* file )
 {
 char buffer[1024];
 char* result = 0;
 int length = 0;

 while( !feof(file) )
  {
  fgets( buffer, sizeof(buffer), file );
  int len = strlen(buffer);
  buffer[len] = 0;

  length += len;
  char* tmp = (char*)malloc(length+1);
  tmp[0] = 0;

  if( result )
   {
   strcpy( tmp, result );
   free( result );
   result = tmp;
   }

  strcat( result, buffer );

  if( strstr( buffer, "\n" ) break;
  }

 return result;
 }

char* line = readLine( stdin );
/* Use it */
free( line );

وآمل أن يساعد هذا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top