English 中文(简体)
Opening a file with path in malloc
原标题:

I m trying to open a file with fopen, but I don t want a static location so I am getting the string in from the user when he/she runs the program. However if a user does not enter one a default file is specified.

Can I just put the malloc var in to the fopen path parameter?

char *file_path_mem = malloc(sizeof(char));
if (file_path_mem != NULL) //Null if out of memory
{
  printf("Enter path to file, if in current directory then specify name
");
  printf("File(default: marks.txt): ");

  while ((c = (char)getchar()) !=  
 )
  {
    file_path_mem[i++] = c;
    file_path_mem = realloc(file_path_mem, i+1 * sizeof(char));
  }
    file_path_mem[i] =   ;
    if (i == 0 && c ==  
 )
    {
      file_path_mem = realloc(file_path_mem, 10 * sizeof(char);
      file_path_mem = "marks.txt";
    }
  }
  else
  {
    printf("Error: Your system is out of memory, please correct this");
    return 0;
  }
  if (i==0)
  {
    FILE *marks_file = fopen("marks.txt", "r");
  }
  else
  {
    FILE *marks_file = fopen(file_path_mem, "r");
  }
  free(file_path_mem);

As you might have guess I am a c novice so if I have done something horrible wrong, then sorry.

最佳回答

realloc is relatively more expensive than the rest of your loop, so you might as well just start with a 128 byte buffer, and realloc another 128 bytes if you fill that up.

I suggest some of the following changes:

define your default location at the top of the file

char* defaultLocation =  myfile.txt ;
char* locationToUse;

use constants instead of hard coding numbers in your code (like the 10 you have in there)

int DEFAULT_INPUT_BUFFER_SIZE = 128;
char* userInputBuffer = malloc(sizeof(char) * DEFAULT_INPUT_BUFFER_SIZE) );
int bufferFillIndex = 0;

only reallocate infrequently, and not at all if possible (size 128 buffer)

while ((c = (char)getchar()) !=  
 )
  {
    file_path_mem[bufferFillIndex++] = c;
    if (bufferFillIndex % DEFAULT_INPUT_BUFFER_SIZE == 0)
    {
        realloc(file_path_mem, (bufferFillIndex + DEFAULT_INPUT_BUFFER_SIZE) * sizeof(char);
    }
  }
问题回答

This is not doing what you think it is:

file_path_mem = realloc(file_path_mem, 10 * sizeof(char);
file_path_mem = "marks.txt";

What you want to do is change that second line to copy the default name into the allocated buffer:

strcpy(file_path_mem, "marks.txt");

You CAN pas the char* returned from malloc straight into fopen. Just make sure it contains valid data. Though make sure you strcpy the new string in as R Samuel points out.

Btw, your use of realloc will give pretty awful performance. Realloc works by seeing if there is enogh space to grow the memory (This is not guranteed, realloc must just return a block that is the newSize containing the old data). If there isn t enough space, it allocs a new block of the new size and copies the old data ot the new block. Obviously this is suboptimal.

You are better off allocating a block of, say, 16 chars and then , if you need more than 16, realloc ing a further 16 chars. There will be a bit of memory wastage but you are not, potentially, copying anything like as much memory around.

Edit: Further to that. For a string that contains 7 character. Using your realloc every byte scheme you will generate the following processes.

alloc 1 byte
alloc 2 bytes
copy 1 byte
free 1 byte
alloc 3 bytes
copy 2 bytes
free 2 bytes
alloc 4 bytes
copy 3 bytes
free 3 bytes
alloc 5 bytes
copy 4 bytes
free 4 bytes
alloc 6 bytes
copy 5 bytes
free 5 bytes
alloc 7 bytes
copy 6 bytes
free 6 bytes
alloc 8 bytes
copy 7 bytes

This is 8 allocations, 7 frees and a copy of 28 bytes. Not to mention the 8 bytes you assign to the array (7 characters + 1 null terminator).

Allocations are SLOW. Frees are SLOW. Copying is much slower than not copying.

For this example using my allocate 16 bytes at a time system you alloc once, assign 8 bytes. No copies and the only free is when you ve finished with it. You DO waste 8 bytes though. But ... well ... 8 bytes is nothing in the grand scheme of things...

Should not be an issue here but for realocation you should state the new size like that

file_path_mem = realloc(file_path_mem, (i+1) * sizeof(char));

You could simplify this greatly with getline(), assuming it is available on your system:

printf("Enter path to file, if in current directory then specify name
");
printf("File(default: marks.txt): ");

int bufSize = 100;
char* fileNameBuf = (char*) malloc(bufSize + 1);
int fileNameLength = getline(&fileNameBuf, &bufSize, stdin);

if(fileNameLength < 0)
{
    fprintf(stderr, "Error: Not enough memory.
")
    exit(1);
}

/* strip line end and trailing whitespace. */
while(fileNameLength && fileNameBuf[fileNameLength - 1] <=    )
    --fileNameLength;
fileNameBuf[fileNameLength] = 0;

if(!fileNameLength)
{
    free(fileNameBuf); /* Nothing entered; use default. */
    fileNameBuf = "marks.txt";
}

FILE *marks_file = fopen(fileNameBuf, "r");

if(fileNameLength)
    free(fileNameBuf);

I don t know if your C supports in-block declarations, so I ll let you fix that if needed.

EDIT: Here s a getline tutorial.

As a learning experience I would second the suggestions of others to expand your buffer by more than one byte. It won t make any difference if it s not in a loop but calling realloc() on each byte would be unacceptable in other contexts.

One trick that works fairly well is to double the size of the buffer every time it fills up.

On the other hand, if you really just want to open a file and don t care about writing the world s greatest name loop, then standard procedure is to simplify the code even at the price of a limit on file name length. There is no rule that says you have to accept silly pathnames.

FILE *read_and_open(void)
{
  char *s, space[1000];

  printf("Enter path to file, if in current directory then specify name
");
  printf("File(default: marks.txt): ");

  fgets(space, sizeof space, stdin);
  if((s = strchr(space,  
 )) != NULL)
    *s = 0;
  if (strlen(space) == 0)
    return fopen("marks.txt", "r");
  return fopen(space, "r");
}




相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...

热门标签