i m using fgets to read line form .txt file. i m passing an array as the first argument. different lines fill in different amount of space in the array, but i want to know the exact length of the line that is read and make decision based in that. is it possible?
FILE * old;
old = fopen("m2p1.txt","r");
char third[100];
fgets(third,sizeof(third),old);
now if i ask for sizeof(third), its obviously 100 because i declared so myself (i cant declare 'third' array without specifying the size) but i need to get the exact size of the line read from file(as it may not fill in the enitre array).
is it possible? what should do?
If fgets succeeds, it'll read a string into your buffer. use strlen() to find its length.
char third[100];
if(fgets(third,sizeof(third),old) != NULL) {
size_t len = strlen(third);
..
}
Related
I'm building a program that reads in a file and then stores each line in an array for manipulation. The input file has a single string on each line, and I want to store each read word in its own slot in a single array. This in an example input file:
This
is
a
test
file
I'm trying to use this with the kernel level read command. This is what I got:
const int recordSize = 1024;
char buffer [recordSize];
int n = 0;
char word[10][50];
while ((n = read(fd_in, buffer, recordSize)) > 0) {
sscanf(buffer,"%s\n%s",word[0],word[1]);
}
The file is read in and stored in buffer. Then I want to put each line into the word array. I made it to hold 10 words of 50 characters length. The purpose of doing something like this is so that I can do something like, change word[0] in one way and alter word[3] in another way.
What I tried is using sscanf. The only issue is that in order for it to know to read on to the next line, I need to use \n and another %s. Since I don't know how long the input file it, this isn't a viable solution.
Right now I'm stuck on how to nondeterministically read line 1, store it in array slot 0, and move on to the next line, repeating for line 2 and slot 1, etc.
I want to get a string from the user, in a char array that have no fixed length. The length should be equal to the, length of the string that the user enters. I tried malloc(), but that also requires the size to be specified. Please help.
Please mark it, I want to use a char array, not a string type.
C strings do not pack their length with them. Every C string is a plain array of characters, with a null after the last char to indicate its end. Standard functions from the C IO library will generally receive, therefore, an array of chars and write data into it. The array will have to be big enough to hold everything that is typed by the user. Most functions won't even check for buffer overflows.
Now what you can do is ask first for the max length of the string the user is going to type and allocate exact memory, or you can declare a huge array and define its size as the max string length.
char bigBuffer[2048];
fgets(bigBuffer, 2048, stdin);
fgets() allows you to specify the maximum number of chars you are taking in. If the user types more than 2048 chars, in this example, fgets() it will return with an error and prevent your program from crashing.
It is not possible to allocate a memory with infinite length. Every memory is bound by size one way or other.
There are two ways to handle your situation.
1. Allocate a large memory which will not overrun any possible user input.
2. [Better Option] Use reasonable size memory and use function with length check like, fgets, to get user input.
What you need is a basic unlimited input function. The idea is to allocate a reasonably sized buffer for input, begin reading one char at a time, and if you exceed the buffer size to realloc it and increase its size.
You could optimize this a bit by reading strings the length of the remaining space, but that gets complicated and fiddly. Mainly not worth it.
I wrote this code off the top of my head so it probably won't compile and work as-is, but it should give you the basic idea.
char *buffer = malloc(100);
size_t bufferLen = 100;
size_t currLen = 0;
int c;
while ((c = getchar()) != EOF && c != '\n')
{
if (currLen > bufferLen-1) // -1 because must leave room for null terminator
{
bufferLen += 100;
buffer = realloc(buffer, bufferLen);
buffer[currLen++] = c;
}
else
buffer[currLen++] = c;
}
buffer[currLen] = '\0';
This can be done in indirect way.
Read one character at a time from input. Using malloc/realloc allocate memory in increasing fashion. It is not of constant order time and constant order memory algo but your functionality can be achieved.
Here is the code snippet for that.
char ch;
int count=0;
char *charArray=NULL;
printf("Enter string\n");
while((ch=getchar())!='\n')//This condition can be changed according to needs
{
count=count+1;
charArray=(char *)realloc(charArray,count);
charArray[count-1]=ch;
}
You create the array after the user has entered the string. Can't remember exact C syntax but something along the lines of
string word = "";
scanf("%s", word");
char myArray[word.length];
All right: So I have a file, and I must do things with it. Oversimplifying, the file has this format:
n
first name
second name
...
nth name
random name
do x⁽¹⁾, y⁽¹⁾ and z⁽¹⁾
random name
do x⁽²⁾, y⁽²⁾, z⁽²⁾
...
random name
do x⁽ⁿ⁾, y⁽ⁿ⁾, z⁽ⁿ⁾
So, the actual details are not important.
The problem is: I'll have to declare a variable n, I have an array name[MAX], and I'll fill this array with the names, from name[0] to name[n-1].
Alright, the problem is: How can I get this input, if I don't know previously how many names do I have?
For example, I could do it just fine if that was an user input, from the keyboard: I would do it like this:
int n; char name[MAX];
scanf( "%d", &n);
int i; for (i = 0; i < n; i++)
scanf( "%s", &N[i]);
And I could go on, do the whole code, but you get the point. But, my input now comes from a file. I don't know how can I get the input, all I can do is to fscanf() the whole file, but since I don't know its size (the first number will determine it), I can't do it. As far as I know (please correct me if that's not true, I am very new to this), we can't use the command "for" and get the numbers gradually as if that was coming from the keyboard, right?
So, the only exit I see is to find a way to read a particular line from the file. If I can do this, the rest is easy. The thing is, how can I do that?
I google'd it, I even found some questions in there, though it didn't make any sense at all. Apparently, reading a particular line from a file is really complicated.
This is from a beginner problem set, so I doubt it is something that complicated. I must be missing something very simple, though I just don't know what it is.
So, the question is: How would you do it, for instance?
How to scan the first number n from the file, and then, scan the others 'n' names, assigning each one to an element in an array (first name = name[0], last name = name[n - 1])?
I would suggest looking into End Of File.
while(!eof(fd))
{
...code...
}
Mind you my C knowledge is rusty, but this should get you started.
IIRC eof returns a value (-1) so that's why you need to compare it to something. Here fd being file descriptor of the file you are reading.
Then after parse of text or count of lines you have your 'n'.
EDIT: Since I'm obviously more tired then I thought(didn't notice your 'n' at the top).
Read first line
malloc for 'n' size array
for loop to iterate names.
Here you go.. I leve compiling and debugging as an exercise for the student.
The idea is to slurp the whole file into a single array if you files are always small.
This is so much more efficient than scanf().
char buf[100000], *bp, *N[1000]; // plenty big
memset( buf, '\0', sizeof buf );
if ( fgets( buf, sizeof(buf), fd ) )
{
int n = 0;
char *bp;
if ( buf[(sizeof buf)-2)] != '\0' )
{ // file too long for buffer
printf( stderr, "trouble: file too large: %d\n", (int)(sizeof buf));
exit(EXIT_FAILURE);
}
// now replace each \n with a \0, remembering where each line is.
for ( bp = buf, bp = strchr( bp, '\n' ); bp++ )
N[n++] = bp;
}
If you want to read any size files you need to read the file in chunks, calloc()ing each chunk before a read, and carefully handling of the line fragments left at the end of the current buffer to move them to the next buffer and then properly continuing you reads.
Unless you have a limit on how many lines you can read the N may need to also be set up in chunks, but this time remalloc() might be your friend.
Since the given format seems to imply that the number of names n is given as the first entry in the file, it would be possible to use the style of reading that the OP describes when reading from stdin. Use fscanf to read the first integer from the file (n), then use malloc to allocate the array(s) for the names, then use a for loop up to n to read the names.
However, I am unsure of the meaning of the example data following that with the do x⁽¹⁾, y⁽¹⁾ and z⁽¹⁾ format. Perhaps I am not understanding part of the question. If it means there are potentially more than n names, then you can use realloc to grow the size of the array. One way of growing the array that is not uncommon is to double the length each time.
I am trying to read Data from a Text file & storing it inside a structure having one char pointer & an int variable.
During fetching data from file I know that there will be one string to fetch & one integer value.
I also know the position form where I have to start fetching.
What I don't know is size of the string.
So, how can I allocate memory for that String.
Sample code is here :
struct filevalue
{
char *string;
int integer;
} value;
fseek(ptr,18,SEEK_SET);//seeking from start of file to position from where I get String
fscanf(ptr,"%s",value.string);//ptr is file pointer
fseek(ptr,21,SEEK_CUR);//Now seeking from current position
fscanf(ptr,"%d",value.integer);
Thanks in advance for your help.
Either
malloc the maximum possible length
read that much into the malloc'd block
figure out where the real end of the string is
write a \0 into your malloc'd block there so it behaves correctly as a nul-terminated string (and/or save the length too in case you need it)
optionally realloc your block to the correct size
Or
malloc a reasonable guesstimate N for the length
read that much
if you can't find the end of the string in that buffer:
grow the buffer with realloc to 2N (for example) and read the next N bytes into the end
goto 3
write a \0 etc. as above
You said in a comment that the max. string length is bounded, so the first approach is probably fine. You haven't said how you figure out where the string ends, but I'm assuming there is some delimiter, or it's right-filled with spaces, or something.
Did you mean to SEEK_CUR in your second fseek()? if so, then you know the length of the string. Used a fixed sized buffer.
If you know the position of the first structure, and the position of the second structure, you also know the total length of the first structure (position of second - position of first). You also know the size of the integer part of the structure, and therefore you can easily calculate the length of the string.
off_t pos1; /* Position of first structure */
off_t pos2; /* Position of second structure */
size_t struct_len = pos2 - pos1;
size_t string_len = struct_len - sizeof(int);
i assume you open the file in binary mode since you use fseek.
you could read from the file using fgetc() since you don't know the size just allocate a buffer with some initial size like 100, then read char by char placing them into the buffer. monitor if the buffer is large enough to hold the characters and if not realloc() the buffer to a larger size.
I want to load a txt file into an array like file() does in php. I want to be able to access different lines like array[N] (which should contain the entire line N from the file), then I would need to remove each array element after using it to the array will decrease size until reaching 0 and the program will finish. I know how to read the file but I have no idea how to fill a string array to be used like I said. I am using gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) to compile.
How can I achieve this?
Proposed algorithm:
Use fseek, ftell, fseek to seek to end, determine file length, and seek back to beginning.
malloc a buffer big enough for the whole file plus null-termination.
Use fread to read the whole file into the buffer, then write a 0 byte at the end.
Loop through the buffer byte-by-byte and count newlines.
Use malloc to allocate that number + 1 char * pointers.
Loop through the buffer again, assigning the first pointer to point to the beginning of the buffer, and successive pointers to point to the byte after a newline. Replace the newline bytes themselves with 0 (null) bytes in the process.
One optimization: if you don't need random access to the lines (indexing them by line number), do away with the pointer array and just replace all the newlines with 0 bytes. Then s+=strlen(s)+1; advances to the next line. You'll need to add some check to make sure you don't advance past the end (or beginning if you're doing this in reverse) of the buffer.
Either way, this method is very efficient (no memory fragmentation) but has a couple drawbacks:
You can't individually free lines; you can only free the whole buffer once you finish.
You have to overwrite the newlines. Some people prefer to have them kept in the in-memory structure.
If the file ended with a newline, the last "line" in your pointer array will be zero-length. IMO this is the sane interpretation of text files, but some people prefer considering the empty string after the last newline a non-line and considering the last proper line "incomplete" if it doesn't end with a newline.
I suggest you read your file into an array of pointers to strings which would allow you to index and delete the lines as you have specified. There are efficiency tradeoffs to consider with this approach as to whether you count the number of lines ahead of time or allocate/extend the array as you read each line. I would opt for the former.
Read the file, counting the number of line terminators you see (ether \n or \r\n)
Allocate a an array of char * of that size
Re-read the file, line by line, using malloc() to allocate a buffer for each and pointed to by the next array index
For your operations:
Indexing is just array[N]
Deleting is just freeing the buffer indexed by array[N] and setting the array[N] entry to NULL
UPDATE:
The more memory efficient approach suggested by #r.. and #marc-van-kempen is a good optimization over malloc()ing each line at a time, that is, slurp the file into a single buffer and replace all the line terminators with '\0'
Assuming you've done that and you have a big buffer as char *filebuf and the number of lines is int num_lines then you can allocate your indexing array something like this:
char *lines[] = (char **)malloc(num_lines + 1); // Allocates array of pointers to strings
lines[num_lines] = NULL; // Terminate the array as another way to stop you running off the end
char *p = filebuf; // I'm assuming the first char of the file is the start of the first line
int n;
for (n = 0; n < num_lines; n++) {
lines[i] = p;
while (*p++ != '\0') ; // Seek to the end of this line
if (n < num_lines - 1) {
while (*p++ == '\0') ; // Seek to the start the next line (if there is one)
}
}
With a single buffer approach "deleting" a line is merely a case of setting lines[n] to NULL. There is no free()
Two slightly different ways to achieve this, one is more memory friendly, the other more cpu friendly.
I memory friendly
Open the file and get its size (use fstat() and friends) ==> size
allocate a buffer of that size ==> char buf[size];
scan through the buffer counting the '\n' (or '\n\r' == DOS or '\r' == MAC) ==> N
Allocate an array: char *lines[N]
scan through the buffer again and point lines[0] to &buf[0], scan for the first '\n' or '\r' and set it to '\0' (delimiting the string), set lines[1] to the first character after that that is not '\n' or '\r', etc.
II cpu friendly
Create a linked list structure (if you don't know how to do this or don't want to, have a look at 'glib' (not glibc!), a utility companion of gtk.
Open the file and start reading the lines using fgets(), malloc'ing each line as you go along.
Keep a linked list of lines ==> list and count the total number of lines
Allocate an array: char *lines[N];
Go through the linked list and assign the pointer to each element to its corresponding array element
Free the linked list (not its elements!)