簡體   English   中英

如何在C中瀏覽任意長度的字符串數組?

[英]How can I navigate through an array of strings of any length in C?

理解在C中處理直接指針

這是一個代碼,適用於固定數量的項目和固定行長度的字符串數組:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXNAMELEN 100
#define MAXLINELEN 100
#define MAXITEMS 1000

int main(int argc, char ** argv) {

 FILE * infile, * outfile;
 char name[MAXNAMELEN];
 char line[MAXLINELEN];
 char lines[MAXITEMS][MAXLINELEN];
 int i, items = 0;

 printf("Enter a source filename: ");
 fgets(name, sizeof(name), stdin);
 name[strlen(name)-1] = '\0'; // strip newline
 infile = fopen(name, "r");
 while (fgets(line, sizeof(line), infile)) {
        strcpy(lines[items], line);
        items++;
 }

 qsort(lines, items, MAXLINELEN, strcmp);

 printf("Enter a destination filename: ");
 fgets(name, sizeof(name), stdin);
 name[strlen(name)-1] = '\0'; // strip newline
 outfile = fopen(name, "w");
 for (i=0; i<items; i++) {
    fputs(lines[i], outfile);
 }

 fclose(infile);
 fclose(outfile);
}

問題描述和代碼

如果我嘗試讀取MAXLINELENMAXITEMS的input.txt文件,程序運行正常。 現在想象一下我從一個更大的“輸入文件”中逐行讀取,其中最大行長度可以是任何東西,然后我將不得不使用字符指針( char* )來讀取輸入。 char* linesptr[MAXITEMS];

這是我的代碼,我試圖通過換行符分隔的輸入文件逐行完成讀取。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#define MAXNAMELEN 1000
#define MAXLINELEN 1000
#define MAXITEMS 100000

char* linesptr[MAXITEMS];

int
main(int argc, char ** argv) {

 FILE * infile, * outfile;
 char name[MAXNAMELEN];
 char line[MAXLINELEN];

 int i, items = 0;

 printf("Enter a source filename: ");
 fgets(name, MAXNAMELEN, stdin);
 name[strlen(name)-1] = '\0'; // strip newline
 printf("%s infile \n",name);
 infile = fopen(name, "r");
 while (fgets(line, MAXLINELEN, infile)) {
    int length = strlen(line);
    line[length-1] = '\0';
    linesptr[items] = line; *<- I am writing to the same mem location*
    printf("the input string %d is : %s \n",items,  linesptr[items]);
        items++;
 }

 qsort(linesptr, items, MAXLINELEN, strcmp); 
 printf("Enter a destination filename: ");
 fgets(name, sizeof(name), stdin);
 name[strlen(name)-1] = '\0'; // strip newline
 outfile = fopen(name, "w");
 for (i=0; i<items; i++) {
    fputs(linesptr[i], outfile);
 }

 fclose(infile);
 fclose(outfile);
}

問題

我將指針地址復制到數組linesptr的第n個單元格中,其中nth是value=items (這里是代碼中的參考行: linesptr[items] = line; )。 所以當你打印最終的答案,我引用相同的內存地址緩沖區命名line ,在存儲位置line總是指向最近fgets() 我理解錯誤,但我不知道如何解決這個問題。 我將不勝感激任何幫助修復代碼中的錯誤。

將該行復制到動態分配的字符串。

while (fgets(line, MAXLINELEN, infile)) {
    int length = strlen(line);
    if (length > 0 && line[length-1] == '\n') {
        line[length-1] = '\0';
        length--;
    }
    char *linecopy = malloc(length+1);
    strcpy(linecpy, line);
    linesptr[items] = linecpy;
    printf("the input string %d is : %s \n",items,  linesptr[items]);
    items++;
}

如果你想要處理超過MAXITEMS行,你也應該使用malloc()來分配linesptr 當你達到linesptr的當前大小時,你可以使用realloc()來使它更長。 有關詳細代碼參閱從stdin,C讀取未知行數

請參見如何在C中輸入指向char的指針數組? 以正確的方式排序指向字符串的指針數組。

你問一個例子,所以這里是:

以下提議的代碼:

  1. 是為了可讀性而編寫的
  2. 檢查並處理錯誤情況
  3. 利用getline()realloc()
  4. 效率不高,因為它為源文件中的每一行調用realloc()
  5. 正確/安全地使用strcspn()刪除任何(可能的)尾隨換行符
  6. 可以通過將'cleanup'提取到子函數來簡化代碼,而不是在遇到錯誤時重復相同的'清理'代碼。
  7. 使用size_t而不是int作為索引到數組中以避免隱式轉換
  8. 盡可能減少變量的scope
  9. 將適當的第三個參數傳遞給qsort()
  10. 正確實現qsort()compare()輔助函數

現在,建議的代碼:

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


#define MAXNAMELEN 1024

// prototypes
int compare(const void *, const void *);


int main( void )
{
    printf("Enter a source filename: ");
    char name[ MAXNAMELEN ];
    if( !fgets(name, sizeof( name ), stdin) )
    {
        perror( "fgets for input file name failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, fgets for input file name successful

    name[strcspn( name, "\n" ) ] = '\0'; // strip newline
    printf("%s infile \n",name);

    FILE *fp_in = fopen(name, "r");
    if( !fp_in )
    {
        perror( "fopen for input file failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, fopen for input file successful

    char **linesarray = NULL;
    size_t numLines   = 0;

    char   *line      = NULL;
    size_t  lineLen   = 0;

    while( getline( &line, &lineLen, fp_in ) != -1 )
    {
        char ** temp = realloc( linesarray, (numLines+1) * sizeof( char* ) );
        if( !temp )
        {
            perror( "realloc failed" );
            fclose( fp_in );
            for( size_t i = 0; i< numLines; i++ )
            {
                free( linesarray[i]);
            }
            free( linesarray );
            exit( EXIT_FAILURE );
        }

        // implied else, realloc successful

        linesarray = temp;
        linesarray[ numLines ] = line;
        numLines++;

        // prep for next iteration
        line = NULL;
        lineLen = 0;
    }

    free( line );
    fclose( fp_in );

    //puts( "all file read in" );

    qsort( linesarray, numLines, sizeof( char * ), compare );

    //puts( "file sorted" );

    printf("Enter a destination filename: ");

    if( !fgets(name, sizeof(name), stdin) )
    {
        perror( "fgets for output file name failed" );

        for( size_t i = 0; i< numLines; i++ )
        {
            free( linesarray[i]);
        }
        free( linesarray );
        exit( EXIT_FAILURE );
    }

    // implied else, fgets() for output file name successful

    name[strcspn( name, "\n" ) ] = '\0'; // strip newline

    FILE *fp_out = fopen(name, "w");
    if( !fp_out )
    {
        perror( "fopen for output file failed" );

        for( size_t i = 0; i< numLines; i++ )
        {
            free( linesarray[i]);
        }
        free( linesarray );
        exit( EXIT_FAILURE );
    }

    // implied else, fopen for output file successful

    for (size_t i=0; i<numLines; i++)
    {
        if( fputs(linesarray[i], fp_out ) == EOF )
        {
            perror( "fputs failed" );
            fclose( fp_out );

            for( size_t i = 0; i< numLines; i++ )
            {
                free( linesarray[i]);
            }
            free( linesarray );
            exit( EXIT_FAILURE );
        }
    }

    fclose( fp_out );

    for( size_t i = 0; i< numLines; i++ )
    {
        free( linesarray[i]);
    }
    free( linesarray );
}


int compare(const void *ls, const void *rs )
{
    char *leftSide  = *(char**)ls;
    char *rightSide = *(char**)rs;
    return strcmp( leftSide, rightSide );
}

這是讀取文件(大數據),對其進行排序並將其寫入文件的完整工作解決方案:

#include <stdio.h>
#include <string.h> 
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#define MAXNAMELEN 1000
#define MAXLINELEN 5000
#define MAXITEMS 100000

char* linesptr[MAXITEMS];

int compare_function(const void *name1, const void *name2)
{
  const char *name1_ = *(const char **)name1;
  const char *name2_ = *(const char **)name2;
  return strcmp(name1_, name2_);
}

int
main(int argc, char ** argv) 
{

 FILE * infile, * outfile;
 char name[MAXNAMELEN];
 char line[MAXLINELEN];

 int i, items = 0;

 printf("Enter a source filename: ");
 fgets(name, MAXNAMELEN, stdin);
 name[strlen(name)-1] = '\0'; // strip newline
 infile = fopen(name, "r");
 while (fgets(line, MAXLINELEN, infile)) {
    int length = strlen(line);
    line[length-1] = '\0';
    char *linecopy = malloc(length);
    strcpy(linecopy, line);
    linesptr[items] = linecopy;
    items++;
 }

 qsort(linesptr, items, sizeof(char *), compare_function);

 printf("Enter a destination filename: ");
 fgets(name, sizeof(name), stdin);
 name[strlen(name)-1] = '\0'; // strip newline
 outfile = fopen(name, "w");
 for (i=0; i<items; i++) {
    fprintf(outfile, "%s\n", linesptr[i]);
 }
 fclose(infile);
 fclose(outfile);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM