I am trying to read strings from file and add them to my array of structs but when i do i get some random characters at the end of one or two strings.Here is my code for reading strings line by line:
while ((read = getline(&line, &len, fp)) != -1) {
strncpy(&structures[i].id,line,4); //copies the first four characters to my array of structures
...
}
When i print out the structures[0].id it prints "WW23�" when it should be just "WW23".It does that with couple of strings, although not with all of them.
My struct looks like this.
struct observers
{
char id[13];
...
};
It reads from file properly at least it gets the integer values right.
You are not terminating the string. Add '\0' at the end structures[i].id[4] = '\0'. It should work fine.
You probably need to add '\0' as the 5'th character to terminate the string.
Related
Newbie here. I need to create a program that reads strings from a textfile.txt then processes a few characters from it.
The contents of textfile.txt is as below.
JA100200300
FE111222333
MA101202303
I need to reference "JA","100", "200" and "300" separately. I managed to do this with the code below, where I split the string into 11 characters and put it into array. Of course this code works only as you type out the string. I need a way to do the same thing but get the string from a file instead.
while((a[i++]=getchar()) != '\n' && i < 11);
How do I do this? Can I read the file and put each line of string into an array, then read from the array and split each array into multiple arrays? Is that possible? Or read each character from the file and put them into arrays something like fscanf %d but split each character?
You might want something like this:
FILE fp = fopen("data.txt","r");
char line[100] = { 0 }, str1[3], str2[4], str3[4], str4[4];
if (!fp) {
perror("opening file");
exit(1);
}
while(fgets(line,sizeof line,fp)) {
strncpy(str1,line,2);
str1[2] = '\0';
strncpy(str2,&line[2],3);
str2[3] = '\0';
strncpy(str3,&line[5],3);
str3[3] = '\0';
strncpy(str4,&line[8],3);
str4[3] = '\0';
}
I am trying to copy a string array "buff" which holds exactly 1000 lines of "OK" in it. i want to copy buff array into line array but cannot see all the 1000 lines in console output.
Here goes my code:
FILE *fp;
char buff[1000];
char* line[1000];
fp = fopen("protocol1.seq", "r");
int i;
for(i=0;i<=999;i++){
fgets(buff,sizeof(buff),fp);
line[i] = buff;
printf("%s",line[i]);
}
fclose(fp);
You have an array line[] which can hold pointers to up to 1000 lines, and you have an array buff which can hold one line (of up to 999 characters). But you have nowhere to hold 1000 different lines. As written, your line array will end up containing a bunch of copies of the exact same pointer, all pointing to buff, which will contain a copy of just the last line you read.
One way to fix this would be to call malloc to allocate memory for each line as you read it:
fgets(buff,sizeof(buff),fp);
char *buffcopy = malloc(strlen(buff) + 1);
if(buffcopy == NULL) {fprintf(stderr, "out of memory\n"); exit(1); }
strcpy(buffcopy, buff);
line[i] = buffcopy;
you've got a few errors.
Should you need to store all lines in an array it needs 2 dimensions, line and string.
So
char buff[1000][256];
Is probably what your looking for this gives 1000 lines of length 255, the final character space is for the nul byte.
Although char *line[1000] is valid it's not what you mean, was this your first attempt to get a 2d array?
Now use 256 instead of sizeof(buff) as buffer control in fgets.
In c you cannot assign strings with the = operator nor compare with ==, you use strcpy and strcmp respectively.
Rather than printing on the fly in the read loop , it may make debug and development easier to have a print function.
To avoid a weird segmentation fault it makes sense to initialise your array. Use memset setting all bytes to 0
For future reference the format %s prints all characters upto the nul byte, so printf-ing an uninitialised string can cause undefined behaviour, probably a segmentation fault, not always but occurring sometime after the offended %s
Ok I need to read information in from a file. I have to take certain parts of the line apart and do different things with each part. I know the maximum and minimum length of the file but I am doing something wrong when I read in the file and then split it up as I am getting really funny values and stuff when I try to compare methods. The maximum length of any line is 80 character.
The format for each line will be as follows: (I will write them in column form as they would appear in a character array)
0-7 _ 9 10-16 _ 18 19-28_ _31-79
spots 0-7 will contain a string(any being under 8 will have blank spaces)
spots 8,17,29,30 are all blank spaces (Marked by underscores)
spots 10-16 will contain a string (again any being under the max length will have blank spaces at the end)
spot 18 will contain a blank space or a character
spot 19-28 will contain another string (Same as other cases)
spot 31-79 can be filled with a string or may not exist at all depends on the users input.
Right now I am using a buffer of size 82 and then doing strncpy to take certain parts from the buffer to break it up. It appears to be working fine but when I do strcmp I am getting funky answers and the strlen is not giving the char arrays I declared the right length.
(I have declared them as having a max length of 8,9,etc. but strlen has been returning weird numbers like 67)
So if I could just read it in broken up it should completely resolve the issue.
I was hoping there would be a way to do this but am currently unsure.
Any help would be greatly appreciated. I have attached the part of the code where I think the error is.
(I know it isn't good to have the size hardcoded in there but I want to get it working first and then I'll get rid of the magic numbers)
while (fgets(buffer, sizeof buffer, fp) != NULL) /* read a line from a file */
{
if (buffer[0] == '.') //If it is a comment line just echo it do not increase counter
{
printf("%s", buffer);
}
else if (buffer[0] == ' ' && buffer[10] == ' ') // If it is a blank line print blank line do not increase counter
{
printf("\n");
}
else //it is an actual instruction perform the real operations
{
//copy label down
strncpy(label, &buffer[0], 8);
//copy Pnemonic into command string
strncpy(command, &buffer[9], 8);
//copy symbol down
symbol = buffer[syLoc];
//copy operand down
strncpy(operand, &buffer[19], 9);
Funky characters and overlong string lengths are a sign that the strings aren't null-terminated, as C (or at least most of C's library functions) expects them.
strncpy will yield null-terminated strings only if the buffer is greater than the length of the source string. In your case, you want to copy substrings out of the middle of a string, so your strings won't have the null terminator.
You could add the null-terminator by hand:
char label[9];
strncpy(label, &buffer[0], 8);
label[8] = '\0';
But given that you have spaces after the substrings you want anyway, you could also use strtok's approach to make your substrings pointers into the line you have read and overwrite the spaces with the null character:
char *label;
char *command;
label = &buffer[0];
buffer[8] = '\0';
command = &buffer[9];
buffer[9 + 8] = '\0';
This approach has the advantage that you don't need extra memory for the substrings. It has the drawback that your substrings will become invalid when you read the next line. If your substrings don't "live" long enough, that approach might be good for you.
Warning: strncpy function do not add any null termination(\0) at the end of the copied chars.
To protect the target char array you have to manually add a \0after each strncpycall like this:
//copy label down
strncpy(label, &buffer[0], 8);
label[8]='\0';
//copy Pnemonic into command string
strncpy(command, &buffer[9], 8);
command[8]='\0';
//copy symbol down
symbol = buffer[syLoc]; //Ok just a single char
//copy operand down
strncpy(operand, &buffer[19], 9);
operand[9]='\0';
If no '\0' is added, chars will be read until a '\0' is encountered in the address after the readed char array in the memory (buffer overflow).
I'm trying to write a function that removes the rest of a line in C. I'm passing in a char array and a file pointer (which the char array was read from). The array is only supposed to have 80 chars in it, and if there isn't a newline in the array, read (and discard) characters in the file until you reach it (newline). Here's what I have so far, but it doesn't seem to be working, and I'm not sure what I'm doing wrong. Any help would be greatly appreciated! Here's the given information about what the function should do:
discardRest - if the fgets didn't read a newline than an entire line hasn't been read. This function takes as input the most recently read line and the pointer to the file being read. discardRest looks for the newline character in the input line. If newline character is not in the line, the function reads (and discards) characters from the file until the newline is read. This will cause the file pointer to be positioned to the beginning of the next line in the input file.
And here's the code:
void discardRest(char line[], FILE* file)
{
bool newlineFound = FALSE;
int i;
for(i = 0; i < sizeof(line); i++)
{
if(line[i] == '\n') newlineFound = TRUE;
}
if(!newlineFound)
{
int c = getc(file);
while(c != '\n')
{
c = getc(file);
}
}
}
Your way is much too difficult, besides sizeof always giving the size of its operand, which is a pointer and not the array it points to which you think it is.
fgets has thefollowing contract:
return NULL: Some kind of error, do not use the buffer, its content might be indeterminate.
otherwise the buffer contains a 0-terminated string, with the last non-0 being the retained '\n' if the buffer and the file were both large enough.
Thus, this should work:
So, use strlen() to get the buffer length.
Determine if a whole line was read (length && [length-1] == '\n').
As appropriate:
remove the newline character and return.
discard the rest of the line like you tried.
The basic gist is, I'm reading words from a text file, storing them as a string, running a function, and then looping over this multiple times, rewriting that string with every new line read. After this loop is done, I need to deal with a different string. The problem is, the second string's bytes, even though I've memset them to 0 at declaration, are getting overwritten by the extra letters in words longer than the space I've allocated to the first string:
char* currDictWord = malloc(9*(sizeof(char));
char* currBrutWord = malloc(9*(sizeof(char));
memset(currBrutWord, 0, 9);
memset(currDictWord, 0, 9);
...
while (stuff) {
fscanf(dictionary, "%s", currDictWord);
}
...
printf("word: %s\n", currBrutWord);
currBrutWord will not be empty anymore. The two ways I've dealt with this are by either making sure currDictWord is longer than the longest word in the dictionary file (kind of a ghetto solution), and doing a new memset on currBrutWord after the loop. Is there no way to tell C to stop writing stuff into memory I've specifically allocated for a different variable?
Yes: stop using fscanf (and preferably the whole scanf-family), and use fgets instead, it lets you pass the maximum number of bytes to read into the variable.
EDIT: (in response to the comment)
fgets will stop reading until count bytes have been read or a newline has been found, which will be in the string. So after fgetsing the string check if there is a newline at the end of it (and remove if necessary). If there is no newline in the string fgetc from the file until you've found one, like this:
fgets(currDictWord, 9, dictionary);
if(currDictWord[strlen(currDictWord) - 1] != '\n'){
while(fgetc(dictionary) != '\n'); /* no body necssary */
/* the stream-pointer is now a the beginning of the next line */
}
Improper string assignment and that not validating data read from a file.
currBrutWord is overrun because too many chars were written into currBrutWord. The same would have happened had you done:
strcpy(currBrutWord, "123456789"); // Bad as this copy 9+1 char into currBrutWord
When using fscanf(), one could limit the data read via:
fscanf(dictionary, "%8s", currDictWord);
This prevents fscanf() from putting too much data into currDictWord. That part is good, but you still have unexpected data coming from the file. You need to challenge any data from the outside world.
if (NULL == fgets(bigbuf, sizeof bigbuf, dictionary)) {
; handle EOF or I/O error
}
// now parse and validate bigbuf using various tools: strtok(), sscanf(), etc.
int n;
if ((sscanf(bigbuf, "%8s%n", currDictWord, &n) < 1) || (bigbif[n] != '\n')) {
; handle error
}