So I'm trying to open a textfile, which looks something like this:
name 1.52
someothername 2.42
...and so on
Now I have to copy these strings and floats into arrays, so I can mess around with them later in my code. The thing is, I'm having trouble assigning the strings that are being found in the textfile my array that I need somewhere else in my code. The arrays have the space 100, because this is supposed to be the maximum length that I allow. I know that the problem lies here
char a[100];
and here
fscanf(fp, "%s %f\n", &a, &b);
how can I pass my empty array to the fscanf function properly so that it can be "filled"?? I keep getting errors like "warning: format specifies type 'char ' but the argument has type 'char ()[100]' [-Wformat]"
/* reads the list into the arrays name and prices and returns the number of lines (i.e.
elements) that have been read */
int read_priceList(const char* path, char names[100][100],
float price[100]){
FILE *fp = fopen(<path>, "r");
char a[100];
float b;
int i = 0;
if(fp == NULL) {
perror("Error opening File");
return -1;
}
while (!feof(fp) && i < 100) {
fscanf(fp, "%s %f\n", &a, &b);
strcpy(names[i], &a);
price [i] = b;
i++;
}
i--;
fclose(fp);
return i;
}
Also later in my code I want to pass an empty, two dimensional string array to this function, which is also a problem...
warning: incompatible pointer types passing 'char ' to parameter of type 'char ()[100]
First, I initialize them (this now happens in the main function, which calls the read_pricelist function)
char namesPricelist[100][100];
float prices[100];
and then I want to call the readPricelist function and give them these parameters.
readPricelist(<path>, &namespricelist[0][0], &prices[0]);
I'm starting to lose my mind, please help...
Among the things wrong with your function:
Regarding the warning, you're passing a char (*)[100] as a formatted target expecting a target of char *. The value you should be passing is the base address of the Nth element needing to be populated.
while (!feof(fp)...) is wrong Read this to see why.
In conjunction with the above, you never validate the fscanf did, in fact, actually work. Rather, you assume it did and blindly throw indeterminate data in to your output buffer. This is especially dangerous when the loop is first entered. If the first fscanf fails to parse anything the array a[] is left utterly indeterminate and the ensuing strcpy will be searching for a terminator to stop, but have no valid string populated in a with which to do so. If you're (un)lucky it will fine a null byte 0x00 somewhere within the first 100 chars, but such behavior is completely undefined.
You leave yourself open to a potential buffer overrun with your wide-open %s format. It should be length-limited.
You needlessly read data into temporaries. fscanf can read properly formatted data directly in your output targets; there is no need for intermediate targets and copying.
Applying all of the above can be done while significantly reducing the code-load, and is worth considering:
int read_priceList(const char* path, char names[100][100], float price[100])
{
FILE *fp = fopen(path, "r");
int i = 0;
if(fp == NULL)
{
perror("Error opening File");
return -1;
}
while (i<100 && fscanf(fp, "%99s %f", names[i], price+i) == 2)
++i;
fclose(fp);
return i;
}
There is still more that can be done, but this should get you considerably further down the road.
Related
I am in school and got an assignment to write a C program that takes an input from a user then scans a file and returns how many times that word shows up in a file. I feel like I got it 90% done, but for some reason I can't get the while loop. When I run the program it crashes at the while loop. Any help or guidance would be greatly appreciated.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
int main() {
char input[50], file[50], word[50];
int wordcount;
printf("Enter a string to search for\n");
scanf("%s", input);
printf("Enter a file location to open\n");
scanf("%s", file);
FILE * fp;
fp = fopen("%s", "r", file);
while (fscanf(fp, "%s", word) != EOF) {
if (strcmp(word, input)) {
printf("found the word %s\n", input);
wordcount++;
}
}
printf("The world %s shows up %d times\n", input, wordcount);
system("pause");
}
You have 2 problems:
fp = fopen("%s", "r", file);
is incorrect, fopen expects only two arguments, not three. The correct version
is
fp = fopen(file, "r");
Note that there is no feature in the C language that allows you to construct
strings from variables like this "%s", variable1. This only works for function
like printf that read a format and interpret the format base on a fix set of
rules you can see here.
The second problem is this:
if (strcmp(word, input))
strcmp is used to compared two strings, however it return 0 when the strings
are equal, non-zero otherwise. So the correct check should be
if(strcmp(word, input) == 0)
{
printf("found the word %s\n", input);
wordcount++;
}
One last thing: when you read a string with scanf, you should limit the amount
of characters to be read, otherwise you will overflow the buffer and this yield
undefined behaviour which could lead to a segfault.
input is a char[50], so it can hold at most 49 characters, the better
scanf call would be
scanf("%49s", input);
with this you are making sure not to write beyond the bounds of the array.
Fotenotes
1The string "%s" has no real meaning in the C language, like any
other string it is merly a sequence of characters that ends with the
'\0'-terminating character. The memory layout for this strings is
+---+---+----+
| % | s | \0 |
+---+---+----+
The printf family of functions however give certains sequences of characters
(the ones beginning with %) a well defined meaning. They're used to determine the type of the variable that should
be used when printing as well as other format options. See the printf documentation for more information about that. You have to
remember however, that this type of constructs only works with printf because
printf was design to work this way.
If you need to construct a string using values of other variables, then you need
to have an array with enough space and use a function like sprintf. For
example:
const char *base = "records";
int series = 8;
char fn[100];
sprintf(fn, "%s%d.dat", base, series);
// now fn has the string "records8.dat"
FILE *fp = fopen(fn, "r");
...
But in your case this is unnecessary because the whole filename was already
stored in variable file, so construction a new string based on file is not
needed.
You are trying to open a file named "%s", which I'm pretty sure does not exist. If you had checked the return from fopen, you could have figured it out yourself.
I am familiar with the sizeof operation in C, but when I use it for the string "1234abcd" it only returns 4, which I am assuming is accounting for the last 4 characters.
So how would I get this to be a string of size 8?
specific code is as follows:
FILE *in_file;
in_file = fopen(filename, "r");
if (in_file == NULL) {
printf("File does not exist\n");
return 1;
}
int val_to_inspect = 0;
fscanf(in_file, "%x", &val_to_inspect);
while (val_to_inspect != 0) {
printf("%x", val_to_inspect);
int length = sizeof val_to_inspect;
printf("%d", length);
Again, the string that is being read from the file is "1234abcd", just to clarify.
There're a couple of issues here:
sizeof operator returns the size of the object. In this case it returns the size of val_to_inspect, which is an int.
http://en.cppreference.com/w/cpp/language/sizeof
fscanf reads from a stream and interprets it. You are only scanning an integer ("%x"), not a string.
http://en.cppreference.com/w/cpp/io/c/fscanf
Lastly, if you actually had a nil-terminated string, to get its length you could use strlen().
TL;DR, to get the length of a string, you need to use strlen().
That said, be a little cautious while using sizeof, it operates on the data type. So, if you pass a pointer to it, it will return you the size of the pointer variable, not the length of the string it points to.
In several important ways, only some of which have anything to do with sizeof, you are mistaken about what your code actually does.
FILE *in_file;
in_file = fopen(filename, "r");
if (in_file == NULL)
{
printf("File does not exist\n");
return 1;
}
Kudos for actually checking whether fopen succeeded; lots of people forget to do that when they are starting out in C. However, there are many reasons why fopen might fail; the file not existing is just one of them. Whenever an I/O operation fails, make sure to print strerror(errno) so you know the actual reason. Also, error messages should be sent to stderr, not stdout, and should include the name of the affected file(s) if any. Corrected code looks like
if (in_file == NULL)
{
fprintf(stderr, "Error opening %s: %s\n", filename, strerror(errno));
return 1;
}
(You will need to add includes of string.h and errno.h to the top of the file if they aren't already there.)
int val_to_inspect = 0;
fscanf(in_file,"%x", &val_to_inspect);
This code does not read a string from the file. It skips any leading whitespace and then reads a sequence of hexadecimal digits from the file, stopping as soon as it encounters a non-digit, and immediately converts them to a machine number which is stored in val_to_expect. With the file containing 1234abcd, it will indeed read eight characters from the file, but with other file contents it might read more or fewer.
(Technically, with the %x conversion specifier you should be using an unsigned int, but most implementations will let you get away with using a signed int.)
(When you get more practice in C you will learn that scanf is broken-as-specified and also very difficult to use robustly, but for right now don't worry about that.)
while (val_to_inspect != 0) {
printf("%x", val_to_inspect);
int length = sizeof val_to_inspect;
printf("%d", length);
}
You are not applying sizeof to a string, you are applying it to an int. The size of an int, on your computer, is 4 chars, and that is true no matter what the value is.
Moreover, sizeof applied to an actual C string (that is, a char * variable pointing to a NUL-terminated sequence of characters) does not compute the length of the string. It will instead tell you the size of the pointer to the string, which will be a constant (usually either 4 or 8, depending on the computer) independent of the length of the string. To compute the length of a string, use the library function strlen (declared in string.h).
You will sometimes see clever code apply sizeof to a string literal, which does return a number related to (but not equal to!) its length. Exercise for you: figure out what that number is, and why sizeof does this for string literals but not for strings in general. (Hint: sizeof s will return a number related to s's string length when s was declared as char s[] = "string";, but not when it was declared as char *s = "string";.)
As a final note, it doesn't matter in the grand scheme of things whether you like your opening braces on their own lines or not, but pick one style and stick to it throughout the entire file. Don't put some if opening braces on their own lines and others at the end of the if line.
It's better to create own counter to find the length of "1234abcd" by reading the character by character.
FILE *in_file;
char ch;
int length=0;
in_file = fopen("filename.txt", "r");
if (in_file == NULL)
{
printf("File does not exist\n");
return 1;
}
while (1) {
ch = fgetc(in_file);
printf("%c", ch);
if (ch == EOF)
break;
length++;
}
fclose(in_file);
printf ("\n%d",length);
Everyone, thank you for all the feedback. I realize I made a lot of mistakes with the original post, but im just switching to c from c++, so a lot of the things I'm used to cant really be applied the same way. This is all tremendously helpful, it's good to have a place to go to.
Len=sizeof(your string)/sizeof(char)-1
-1 is eof character null
If you want to get length of any from specific begining index just do Len-index
My problem is when I try to save the string (series[0]) Inside (c[0])
and I display it, it always ignore the last digit.
For Example the value of (series[0]) = "1-620"
So I save this value inside (c[0])
and ask the program to display (c[0]), it displays "1-62" and ignores the last digit which is "0". How can I solve this?
This is my code:
#include <stdio.h>
int main(void)
{
int price[20],i=0,comic,j=0;
char name,id,book[20],els[20],*series[20],*c[20];
FILE *rent= fopen("read.txt","r");
while(!feof(rent))
{
fscanf(rent,"%s%s%s%d",&book[i],&els[i],&series[i],&price[i]);
printf("1.%s %s %s %d",&book[i],&els[i],&series[i],price[i]);
i++;
}
c[0]=series[0];
printf("\n%s",&c[0]);
return 0;
}
The use of fscanf and printf is wrong :
fscanf(rent,"%s%s%s%d",&book[i],&els[i],&series[i],&price[i]);
Should be:
fscanf(rent,"%c%c%s%d",&book[i],&els[i],series[i],&price[i]);
You have used the reference operator on a char pointer when scanf expecting a char pointer, also you read a string to book and else instead of one character.
printf("1.%s %s %s %d",&book[i],&els[i],&series[i],price[i]);
Should be:
printf("1.%c %c %s %d",book[i],els[i],series[i],price[i]);
And:
printf("\n%s",&c[0]);
Should be:
printf("\n%s",c[0]);
c is an array of char * so c[i] can point to a string and that is what you want to send to printf function.
*Keep in mind that you have to allocate (using malloc) a place in memory for all the strings you read before sending them to scanf:
e.g:
c[0] = (char*)malloc(sizeof(char)*lengthOfString+1);
and only after this you can read characters in to it.
or you can use a fixed size double character array:
c[10][20];
Now c is an array of 20 strings that can be up to 9 characters long.
Amongst other problems, at the end you have:
printf("\n%s",&c[0]);
There are multiple problems there. The serious one is that c[0] is a char *, so you're passing the address of a char * — a char ** — to printf() but the %s format expects a char *. The minor problem is that you should terminate lines of output with newline.
In general, you have a mess with your memory allocation. You haven't allocated space for char *series[20] pointers to point at, so you get undefined behaviour when you use it.
You need to make sure you've allocated enough space to store the data, and it is fairly clear that you have not done that. One minor difficulty is working out what the data looks like, but it seems to be a series of lines each with 3 words and 1 number. This code does that job a bit more reliably:
#include <stdio.h>
int main(void)
{
int price[20];
int i;
char book[20][32];
char els[20][32];
char series[20][20];
const char filename[] = "read.txt";
FILE *rent = fopen(filename, "r");
if (rent == 0)
{
fprintf(stderr, "Failed to open file '%s' for reading\n", filename);
return 1;
}
for (i = 0; i < 20; i++)
{
if (fscanf(rent, "%31s%31s%19s%d", book[i], els[i], series[i], &price[i]) != 4)
break;
printf("%d. %s %s %s %d\n", i, book[i], els[i], series[i], price[i]);
}
printf("%d titles read\n", i);
fclose(rent);
return 0;
}
There are endless ways this could be tweaked, but as written, it ensures no overflow of the buffers (by the counting loop and input conversion specifications including the length), detects when there is an I/O problem or EOF, and prints data with newlines at the end of the line. It checks and reports if it fails to open the file (including the name of the file — very important when the name isn't hard-coded and a good idea even when it is), and closes the file before exiting.
Since you didn't provide any data, I created some random data:
Tixrpsywuqpgdyc Yeiasuldknhxkghfpgvl 1-967 8944
Guxmuvtadlggwjvpwqpu Sosnaqwvrbvud 1-595 3536
Supdaltswctxrbaodmerben Oedxjwnwxlcvpwgwfiopmpavseirb 1-220 9698
Hujpaffaocnr Teagmuethvinxxvs 1-917 9742
Daojgyzfjwzvqjrpgp Vigudvipdlbjkqjm 1-424 4206
Sebuhzgsqpyidpquzjxswbccqbruqf Vuhssjvcjjylcevcisdzedkzlp 1-581 3451
Doeraxdmyqcbbzyp Litbetmttcgfldbhqqfdxqi 1-221 2485
Raqqctfdlhrmhtzusntvgbvotpk Iowdcqlwgljwlfvwhfmw 1-367 3505
Kooqkvabwemxoocjfaa Hicgkztiqvqdjjx 1-466 435
Lowywyzzkkrazfyjuggidsqfvzzqb Qiginniroivqymgseushahzlrywe 1-704 5514
The output from the code above on that data is:
0. Tixrpsywuqpgdyc Yeiasuldknhxkghfpgvl 1-967 8944
1. Guxmuvtadlggwjvpwqpu Sosnaqwvrbvud 1-595 3536
2. Supdaltswctxrbaodmerben Oedxjwnwxlcvpwgwfiopmpavseirb 1-220 9698
3. Hujpaffaocnr Teagmuethvinxxvs 1-917 9742
4. Daojgyzfjwzvqjrpgp Vigudvipdlbjkqjm 1-424 4206
5. Sebuhzgsqpyidpquzjxswbccqbruqf Vuhssjvcjjylcevcisdzedkzlp 1-581 3451
6. Doeraxdmyqcbbzyp Litbetmttcgfldbhqqfdxqi 1-221 2485
7. Raqqctfdlhrmhtzusntvgbvotpk Iowdcqlwgljwlfvwhfmw 1-367 3505
8. Kooqkvabwemxoocjfaa Hicgkztiqvqdjjx 1-466 435
9. Lowywyzzkkrazfyjuggidsqfvzzqb Qiginniroivqymgseushahzlrywe 1-704 5514
10 titles read
For some reason when building my program, it says that I have this error:
error: invalid conversion from 'char' to 'const char*' [-fpermissive]
strcpy(phrase[counter].word, ch);
I'm not really sure what the compiler means, I've tried changing char ch to const char ch, but that doesn't seem to fix the issue. If anyone could shed some light on this issue that would be great.
Here is the code you can refer to:
const char* clean_word(void);
void create_word(struct Word_setup phrase[], FILE *fp)
{
char ch;
fscanf(fp, "%s", &ch);
strcpy(phrase[counter].word, ch);
strcpy(phrase[counter].word, clean_word());
}
const char* clean_word()
{
int i;
const char *ch = phrase[counter].word;
ch = phrase[counter].word;
for (i = 0; i < M; i++)
{
if (phrase[counter].word[i] == 39 || isalpha(phrase[counter].word[i])) //39 is the ASCII value for: '
i = i; //Just to be there, no reason to it. I just want the program to do nothing if its a letter or '
else
phrase[counter].word[i] = '\0';
}
return ch;
}
Also in case you're wondering what this is for, I'm building a program that will scan a *.txt file and then print out the word with the highest number of appearances, as as well as the number of appearances.
If you've already read my old post, I decided to try writing it without re-allocating space every time the array gets filled, and I just set it to 200 max different types of words. I will change the program once I'm finished so that it reallocates space every time that the array fills up.
The problem is here:
char ch;
fscanf(fp, "%s", &ch);
strcpy(phrase[counter].word, ch);
The strcpy() function expects its second argument to be a pointer to the head of the source string, but ch is a char, not a char * or const char *. As Keith Thompson explained, this is an error because integers are not implicitly convertible to pointers in C (other than a constant expression with value 0). Even if the compiler performed an implicit conversion anyway, the behavior would surely not be what you want.
Moreover, the fscanf() isn't going to do what you want, either, because even though argument &ch is the correct type for the format string it accompanies, it is a pointer to only a single character of storage, and the fscanf will always write outside its bounds if it successfully scans a string (because it must write a string terminator even for a one-character string).
#BLUEPIXY's approach is much better, supposing that phrase[counter].word is a char array, but even there you risk overrunning its bounds. To protect yourself against that, specify a field width. For instance, if phrase[counter].word is an array of 20 chars, then use this ...
fscanf(fp, "%19s", phrase[counter].word);
... to ensure that scanf() does not write more than 20 chars (including a string terminator) to the array.
maybe...
void create_word(struct Word_setup phrase[], FILE *fp)
{
fscanf(fp, "%s", phrase[counter].word);
clean_word();
}
I have a file called pi.txt which contains, as you probably imagine, the numbers of pi.
The format goes like this
Line 1: 3.
Line 2: 14159265358979323846264338327950288419716939937510
Line 3: 58209749445923078164062862089986280348253421170679
and it continues to
Line 20001: 56787961303311646283996346460422090106105779458151
There are 1020001 digits minus the 3 and the .(of 3.14xxxxxx...)
I have to read this file to an array (not a 2D one. What I want to do later will become much harder if I use a 2D array as I imagine it). This is my code:
void fpi();
char **arraypi;
int main(int argc, char *argv[]) {
fpi();
int i;
while (i<=10){
printf("%d", arraypi[i++]);}
return 0;
}
void fpi(){
char pi[1020001];
arraypi = malloc(1020001 * sizeof(int));
FILE *file;
int i=0;
file = fopen("pi.txt", "r");
if (file == NULL){
printf("The file cannot be opened.\n");
exit(1);
}
while (fscanf(file, "%c", &pi)==1){
strcpy(arraypi[i++], pi);
}
fclose(file);
}
I get a segmentation fault and I can't figure out why. I'm sure it has to do with the pointers I'm using and fscanf.
strcpy expects you to give a null terminated character array (string) and you're giving an array of 1020001 characters where except the first character, which is read from the file, everything else is undetermined.
char pi[1020001];
while (fscanf(file, "%c", &pi)==1){ // only one character gets copied to pi
strcpy(arraypi[i++], pi); // strcpy will expect pi to be a string and not just a char
}
Hence it may go on an infinite loop and write beyond the allowed memory allocated for it, thereby corrupting the stack structure and thus leading to the segmentation fault. You're also treading on undefined behaviour when you're doing this.