[英]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: 几个任务似乎是:
char*
-Array ( char**
) char*
-Array( char**
)
char**
by the length of your line char**
进行排序
strlen
and some swap
-function to archieve this (by simple apply sth. like bubblesort ) strlen
一些swap
功能全到archieve这(通过简单的申请某事。像冒泡 ) N
lines of the sortet char**
with printf
printf
输出sortet char**
的前N
行 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.