简体   繁体   English

在C中使用指针代替二维数组字符串

[英]Using pointers instead of 2-D array string in C

I have a problem like here: Write a program to read a multiple line text file and write the 'N' longest lines to stdout. 我有一个类似这里的问题:编写一个程序以读取多行文本文件,并将'N'最长的行写入stdout。 Where the file to be read is specified on the command line. 在命令行上指定要读取的文件的位置。

Now I wrote my program like this: 现在,我这样编写程序:

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

int main(int argc, char *argv[])
{
  int a,k,n,i=0,j;
  int part;
  char ar[1000][1000],str[1000];
  /* char file[200]; */
  /* scanf("%s",file); */
  FILE *f = fopen(argv[1],"r");
  if ( f == NULL || argc < 2)
  {
    return 0;
  }

   fscanf(f,"%d",&a);

   while (fscanf(f,"%s",str)==1)
   {
        strcpy(ar[i++],str);

      for ( k = 0 ; k < i ; k++ )
      {
        for ( j = k ; j < i ; j++)
        {
          if ( strlen(ar[k]) < strlen(ar[j]))
          {
            strcpy(str,ar[k]);
            strcpy(ar[k],ar[j]);
            strcpy(ar[j],str);
          }
        }
      }

   }

   for ( j = 0 ; j < a ; j++ )
   {
    puts(ar[j]);
  }

return 0;
}

First of all it is working well for me but on submission it is giving me runtime error. 首先,它对我来说运作良好,但是在提交时却给了我运行时错误。 Secondly I want to do it using pointers and dynamic allocation of memory. 其次,我想使用指针和动态内存分配来做到这一点。 How can I do that? 我怎样才能做到这一点?

Sorry, I went to bed for some time. 对不起,我上床睡觉了一段时间。 Can you explain me what's wrong with my code. 您能解释一下我的代码有什么问题吗? Why it is not working. 为什么它不起作用。 I think no one explained me where I am doing wrong. 我认为没有人向我解释我做错了什么。 Please let me know how can I draw attention of people after a few hours from posting my question. 请让我知道在发布问题几个小时后如何引起人们的注意。 Again thanks a lot for all of you for giving me so much time. 再次感谢大家给我这么多时间。

If you really want to conserve memory then you should not copy any contents of the file, but instead mmap it into your process and only save the offsets into the longest lines in your code. 如果您确实想节省内存,则不应复制文件的任何内容,而应将其mmap到进程中,而仅将偏移量保存到代码中最长的行中。 On longer files this should give you significantly more performance since it outsources memory management to the kernel. 在较长的文件上,这应该为您提供显着的性能,因为它将内存管理外包给了内核。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>


int main(int argc, char ** argv) {
    char * filename = argv[1];
    if (!filename) {
        fprintf(stderr, "Usage: %s filename\n", argv[0]);
        exit(-1);
    }

    int fd = open(filename, O_RDONLY);
    if (fd < 0) {
        perror("open");
        abort();
    }

    struct stat file_stats;
    if(fstat(fd, &file_stats)) {
        perror("fstat");
        abort();
    }

    char * file_contents = mmap(NULL    // anywhere
        , file_stats.st_size + 1        // file length + 1 byte for null terminator
        , PROT_READ                     // we only need read only
        , MAP_PRIVATE                   // this doesn't really matter since we are read only
        , fd                            // from this file descriptor
        , 0);                           // from beginning

    if (file_contents == MAP_FAILED) {
        perror("mmap");
        abort();
    }

    // optional
    // Expect page references in sequential order.
    // Hence, pages can be aggressively read ahead, and may be freed soon after they are accessed.
    madvise(file_contents, file_stats.st_size + 1, MADV_SEQUENTIAL);

    struct {
        size_t start;
        size_t end;
    } longest_lines[10]; // struct to hold ofsets for longest lines

    memset(longest_lines, 0, sizeof(longest_lines)); // initialise
    int shortest_line_id = 0;

    char * start = file_contents;
    char * next;

    // while we are not at the end
    while (start < file_contents + file_stats.st_size) {
        if (!(next = strchr(start, '\n'))) // if line ternimator wasn't found, then go to the end
            next = file_contents + file_stats.st_size;

        size_t line_length = next - start;

        // if this line is longer then our shortest
        if (line_length > longest_lines[shortest_line_id].end - longest_lines[shortest_line_id].start) {
            longest_lines[shortest_line_id].start = start - file_contents;
            longest_lines[shortest_line_id].end = next - file_contents;

            // determine new shortest line
            int i;
            for (i = 0; i < sizeof(longest_lines)/sizeof(*longest_lines); i++) {
                if (
                longest_lines[i].end - longest_lines[i].start
                <
                longest_lines[shortest_line_id].end - longest_lines[shortest_line_id].start
                )
                    shortest_line_id = i;
            }
        }
        // next line starts at this offset
        start = next + 1;
    }

    int i; // print them
    for (i = 0; i < sizeof(longest_lines)/sizeof(*longest_lines); i++) {
        printf("%.*s\n", (int)(longest_lines[i].end - longest_lines[i].start), file_contents + longest_lines[i].start);
    }

    return 0;
}

Because it seems like some kind of homework or sth. 因为这似乎是某种作业或某事。 I won't provide a full solution. 我不会提供完整的解决方案。 But I will try to give you some peaces that you can start with. 但我会尽力给您一些安心。

You should divide your task by its responsibilities and try to create your programm a little more modular . 您应该按任务划分职责,并尝试创建更具模块化的程序

The several tasks seem to be: 几个任务似乎是:

  1. Get the count of lines in your file 获取文件中的行数
    • You can use a loop with fgets and a counter-variable to do this 您可以使用带有fgets和反变量的循环来执行此操作
  2. Allocate a char* -Array ( char** ) 分配一个char* -Array( char**
    • You can use malloc() with the counter-variable 您可以将malloc()与计数器变量一起使用
  3. Read all lines of your file into the allocated memory-sections and allocate memory for each line 将文件的所有行读入分配的内存部分,并为每一行分配内存
    • You can use getline() to get a pointer to an allocated memory section 您可以使用getline()获取指向已分配内存部分的指针
    • Really getline takes a lot work from you, but you can also combine the following functions to to the same: 真正的getline需要您做很多工作,但是您也可以将以下功能组合在一起:
      • fgets
      • malloc
      • realloc
      • strlen
  4. Sort your char** by the length of your line 按行的长度对char**进行排序
    • You can use strlen and some swap -function to archieve this (by simple apply sth. like bubblesort ) 您可以使用strlen一些swap功能全到archieve这(通过简单的申请某事。像冒泡
  5. Output the first N lines of the sortet char** with printf printf输出sortet char**的前N
  6. Don't forget to free all allocated memory with free() ! 不要忘记使用free()释放所有分配的内存!

For Hints see the following post . 有关提示,请参见以下帖子

Note that the steps I provide do not optimize for memory or cpu-usage. 请注意,我提供的步骤并未针对内存或cpu-usage进行优化。 But if your program works and you understoud what you've done this could be the next step. 但是,如果您的程序正常运行,并且您了解所做的工作,那么下一步可能会是。

Also this task shows the great benefits of modern programming languages where such a task would be a five line script. 此任务还显示了现代编程语言的巨大好处,其中此类任务是五行脚本。 Here's the F# version that performs what you want to archieve: 这是执行您要归档的F#版本:

open System
open System.IO
open System.Linq

[<EntryPoint>]
let main args =
  try
    let linesToPrint = Int32.Parse(args.ElementAt(0))
    let path         = @"C:\Users\XYZ\Desktop\test.txt"
    File.ReadAllLines(path).OrderByDescending(fun line -> line.Length).Take(linesToPrint).ToArray()
    |> Array.iter(printfn "%s")
  with
  | ex -> eprintfn "%s" ex.Message
  0

Note the sortness and the readability of the solution. 注意解决方案的分类可读性 Nevertheless it is worth to program such a task in c or maybe also in assembler to get a deeper understanding for how computers work. 尽管如此,还是值得在c或汇编程序中对此类任务进行编程,以更深入地了解计算机的工作方式。

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

int main(int argc, char *argv[]){
    int a, n=0, i;
    char **ar, str[1000];
    int *lens;

    FILE *f = fopen(argv[1],"r");

    if ( f == NULL || argc < 2){
        return 0;
    }

    fscanf(f,"%d",&a);
    if(NULL==(ar=calloc(a, sizeof(char*))) || NULL==(lens=calloc(a, sizeof(int)))){
        perror("malloc");
        return -1;
    }
    while (fscanf(f, " %999[^\n]", str)==1){
        ++n;
        int len = strlen(str);
        for(i = 0;i < a;++i){
            if(lens[i] < len){
                free(ar[a-1]);
                memmove(&lens[i+1], &lens[i], (a-i-1)*sizeof(int));
                memmove(&ar[i+1], &ar[i], (a-i-1)*sizeof(char*));
                ar[i]=strdup(str);
                lens[i]=len;
                break;
            }
        }
    }
    fclose(f);
    for (i = 0 ; i < n && i < a ; i++ ){
        puts(ar[i]);
        free(ar[i]);
    }
    free(ar);free(lens);

    return 0;
}

If you're happy sticking with your maximum line length of 1000 you can do: 如果您愿意坚持使用最大行长1000,则可以执行以下操作:

char (*ar)[1000] = malloc(a * sizeof *ar);

if (!ar)
    // error handling....

and then use ar as you used it before. 然后像以前一样使用ar

There is a problem : fscanf(f,"%s",str) . 有一个问题: fscanf(f,"%s",str) This reads a single word, and does no length checking. 这将读取一个单词,并且不进行长度检查。 I guess you actually want to read a whole line, and not overflow your buffer: 我猜您实际上是想读整行,而不要溢出缓冲区:

fgets(str, sizeof str, f);

If you want to you can remove the newline from str after this but actually it will make no difference to your program. 如果需要,您可以在此之后从str删除换行符,但实际上这对您的程序没有影响。

There is currently a problem with your algorithm; 您的算法目前存在问题; you read every line into ar . 您将每一行读入ar Instead you should just make ar 's size be a (I presume that a is meant to be N ), take out the line strcpy(ar[i++],str); 相反,您应该仅使ar的大小为a (我假设a的意思是N ),取出strcpy(ar[i++],str); , and only insert the line if it is bigger than the current smallest member. ,并且仅当该行大于当前的最小成员时才插入该行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM