[英]Using pointers instead of 2-D array string in C
我有一个类似这里的问题:编写一个程序以读取多行文本文件,并将'N'最长的行写入stdout。 在命令行上指定要读取的文件的位置。
现在,我这样编写程序:
#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;
}
首先,它对我来说运作良好,但是在提交时却给了我运行时错误。 其次,我想使用指针和动态内存分配来做到这一点。 我怎样才能做到这一点?
对不起,我上床睡觉了一段时间。 您能解释一下我的代码有什么问题吗? 为什么它不起作用。 我认为没有人向我解释我做错了什么。 请让我知道在发布问题几个小时后如何引起人们的注意。 再次感谢大家给我这么多时间。
如果您确实想节省内存,则不应复制文件的任何内容,而应将其mmap
到进程中,而仅将偏移量保存到代码中最长的行中。 在较长的文件上,这应该为您提供显着的性能,因为它将内存管理外包给了内核。
#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;
}
因为这似乎是某种作业或某事。 我不会提供完整的解决方案。 但我会尽力给您一些安心。
您应该按任务划分职责,并尝试创建更具模块化的程序 。
几个任务似乎是:
char*
-Array( char**
)
malloc()
与计数器变量一起使用 getline()
获取指向已分配内存部分的指针 getline
需要您做很多工作,但是您也可以将以下功能组合在一起:
fgets
malloc
realloc
strlen
char**
进行排序
strlen
一些swap
功能全到archieve这(通过简单的申请某事。像冒泡 ) printf
输出sortet char**
的前N
行 free()
释放所有分配的内存! 有关提示,请参见以下帖子 。
请注意,我提供的步骤并未针对内存或cpu-usage进行优化。 但是,如果您的程序正常运行,并且您了解所做的工作,那么下一步可能会是。
此任务还显示了现代编程语言的巨大好处,其中此类任务是五行脚本。 这是执行您要归档的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
注意解决方案的分类和可读性 。 尽管如此,还是值得在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;
}
如果您愿意坚持使用最大行长1000,则可以执行以下操作:
char (*ar)[1000] = malloc(a * sizeof *ar);
if (!ar)
// error handling....
然后像以前一样使用ar
。
有一个问题: fscanf(f,"%s",str)
。 这将读取一个单词,并且不进行长度检查。 我猜您实际上是想读整行,而不要溢出缓冲区:
fgets(str, sizeof str, f);
如果需要,您可以在此之后从str
删除换行符,但实际上这对您的程序没有影响。
您的算法目前存在问题; 您将每一行读入ar
。 相反,您应该仅使ar
的大小为a
(我假设a
的意思是N
),取出strcpy(ar[i++],str);
,并且仅当该行大于当前的最小成员时才插入该行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.