Read from standard input into a C array - c

The input is
name number number
like the example
bank 1 10
I need to read input into a matrix n lines by 3 columns like the next example
{ bank, 1, 10,
bank2, 2, 15,
bank3, 3, 20 }
My main difficulty is reading the name and storing into the matrix. The name can vary from 1 to 41 characters.
I tried doing it the following way but I don't know a way to ignore the blank spaces in the input and how to make the for loop only count until the word is read.
for (b=0; b<41;b++) {
scanf("%s ",&nome[i]);
}
scanf("%d %d",&rating,&ref);
n[i][0] = *nome;
n[i][1] = rating;
n[i][2] = ref;
I just started learning programming in C so I can't use advanced things in my code.

You are trying to read a string one character at a time, but using the edit descriptor for reading a whole string. You're trying to make it harder than it needs to be.
Also, the term "matrix" is normally understood to mean a 2-dimensional array of elements all the same type, whereas it sounds like you want a 1-dimensional array of structs containing members of different types. For example:
#define MAX_BANKS 10
struct bank {
char nome[42];
int rating;
int ref;
};
struct bank banks[MAX_BANKS];
int num_banks = 0;
/* ... */
void read_banks(void) {
while (num_banks < MAX_BANKS) {
int fields;
fields = scanf("%41s %d %d", banks[num_banks].nome,
&banks[num_banks].rating, &banks[num_banks].ref);
if (fields != 3) {
/* handle error */
break;
} else {
num_banks += 1;
}
/* ... */
}
}

In this example I have interpreted your "matrix" requirement, such that each line of the input fills in a struct having different field types, so we end up with a 1-D array of the struct instead of a 2-D array of differing data types.
And instead of entering the data from the keyboard, which is so boring every time you test the program, I have put your data in a file and read from that - although the technique is quite similar.
Also, because your input format is not consistent, I have skipped any chars that don't form part of the data, see delims.
The program is possibly rather more complicated than you would have liked, but I hope it can help you do what you want. The complexity level rose when I decide not to use a fixed length string in the struct but a pointer to string memory, allocated for a variable length string.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *nome;
int rating;
int ref;
} customer;
void fatal(char *msg) {
printf("%s\n", msg);
exit (1);
}
int main()
{
FILE *fp; // for fopen
char line[1000]; // for fgets
char *delims = ", {}\t\r\n"; // for strtok
char *sptr; // for strtok
customer *mark = NULL; // an empty array
int marks = 0; // number of customers
int len; // length of input string
fp = fopen("input.txt", "r"); // open the file
if (fp == NULL) // did it open?
fatal("Cannot open file");
while (fgets(line, 1000, fp) != NULL) { // each line of file
mark = realloc(mark, sizeof(customer) * (marks+1)); // extend
if (mark == NULL)
fatal("Cannot extend array"); // failed extend the array
sptr = strtok(line, delims); // split first field
if (sptr == NULL)
fatal("Cannot get first field");
len = strlen(sptr); // length of bank name
mark[marks].nome = malloc(len+1); // memory for the string
if (mark[marks].nome == NULL)
fatal("Cannot allocate string array");
strcpy(mark[marks].nome, sptr); // copy string to struct
sptr = strtok(NULL, delims); // split second field
if (sptr == NULL)
fatal("Cannot get second field");
mark[marks].rating = atoi(sptr); // extract number
sptr = strtok(NULL, delims); // split third field
if (sptr == NULL)
fatal("Cannot get third field");
mark[marks].ref = atoi(sptr); // extract number
marks++; // one more record
}
fclose (fp);
// print the results (re-using len for convenience)
for (len=0; len<marks; len++)
printf("%s %d %d\n", mark[len].nome, mark[len].rating, mark[len].ref);
// release the data array
for (len=0; len<marks; len++)
free(mark[len].nome);
free(mark);
return 0;
}
Input file:
{ bank, 1, 10,
bank2, 2, 15,
bank3, 3, 20 }
Program output:
bank 1 10
bank2 2 15
bank3 3 20

Since you are working with a collection of different types of information (e.g. char*, int, int), the proper way to collect this information is in a structure (or struct). You have two choices on how to create space for any array or array of struct, (1) statically allocate on stack, or (2) dynamically allocate on heap. Given your question requirement, static allocation is the most basic. However, it is not as flexible as dynamically allocating the data, and you are limited to the initial size you choose.
Just as with storing the data, you have choices on how you read the data from stdin. As a general proposition, when reading from stdin, the preferred way is to read a line-at-a-time into a buffer and then parse the buffer for the desired content. Just as above, line input is more flexible than squeezing the data into a scanf format string, but is a bit more involved. For purposes here, we will use scanf, but know that line-input with getline or fgets provide certain advantages.
Next, you can just declare the number of structs you need, or you can take the time to initialize all the values in each of the structs. (this has advantages as you will see below). Aside for allowing some iteration tricks, the primary reason you initialize all your variables is to prevent the possibility of reading from them uninitialized. Reading an uninitialized variable results in Undefined Behavior (bad). So take the time to learn how to initialize each of your variable types.
With that said, you can tell there are a number of valid ways to approach any problem. How you do it is up to you, as long as you do it correctly. Here is another approach to meet your requirements. Note that the maximum name length MAXNM and maximum number of lines to read MAXLN are defined at the top of the code. This allows you to easily adjust the values later on. Let me know if you have any questions:
#include <stdio.h>
#define MAXNM 41
#define MAXLN 100
typedef struct mix {
char name[MAXNM + 1];
int num1;
int num2;
} mix;
int main (void) {
/* initialize array of structs & variables */
mix array[MAXLN] = {{ {0}, 0, 0 }};
size_t i = 0;
size_t read = 0;
/* read array of struct contents from stdin */
while (scanf ("%s %d %d", array[i].name, &array[i].num1, &array[i].num2) == 3) {
i++;
/* check if lines > MAXLN allowed */
if (i >= MAXLN) {
fprintf (stderr, "warning: lines read from stdin exceed MAXLN.\n");
break;
}
}
/* set the number of elements read to i */
read = i;
/* iterate over elements using 'read' */
printf ("\nIterating array using 'while (i < read)'\n\n");
i = 0;
while (i < read) {
printf (" array[%zu] %-41s %4d %4d\n", i, array[i].name, array[i].num1, array[i].num2);
i++;
}
/* iterate over array by virtue of initization of name to 0/null */
i = 0;
printf ("\nIterating array using 'while (array[i].name[0])'\n\n");
while (array[i].name[0]) {
printf (" array[%zu] %-41s %4d %4d\n", i, array[i].name, array[i].num1, array[i].num2);
i++;
}
printf ("\n");
return 0;
}
Input
$ cat dat/staticstruct.txt
TheNamesofVaryingWidth 123 456
SomeOtherName 234 567
Bank_1 12 34
Bank_2 23 45
Bank_3 34 56
OneLastNameThatHasCloseToTheMaximumChars 777 9999
Output
$ ./bin/ptrarraystatic < dat/staticstruct.txt
Iterating array using 'while (i < read)'
array[0] TheNamesofVaryingWidth 123 456
array[1] SomeOtherName 234 567
array[2] Bank_1 12 34
array[3] Bank_2 23 45
array[4] Bank_3 34 56
array[5] OneLastNameThatHasCloseToTheMaximumChars 777 9999
Iterating array using 'while (array[i].name[0])'
array[0] TheNamesofVaryingWidth 123 456
array[1] SomeOtherName 234 567
array[2] Bank_1 12 34
array[3] Bank_2 23 45
array[4] Bank_3 34 56
array[5] OneLastNameThatHasCloseToTheMaximumChars 777 9999

Related

How do i copy n characters for m lines in a file (in c)?

I have a file of 1000 lines with up to 70 characters in them. I want to copy the 13 first in a table, the 15th-30th in another table... i tried many different things without success, here's one of them :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define size_num 13 // 13 character with \0 included
#define line 1000
#define carac 300 // like 300 characters per line
int verifFile(FILE*pf) //check file
{
if (pf == NULL)
{
printf("can't open file");
return 1;
}
else
{
return 0;
}
}
int main()
{
float td,tf;
td=clock(); //count execution time of program
FILE* pf=NULL;
pf = fopen("call.txt", "r");
verifFile(pf);
char str[line];
char number[line][size_num];
while(fgets(str,line,pf)!= NULL)
{
printf("%s", str);
number[line][size_num]=str[line]; // here i want number to copy the 13 first characters
//of each 1000 lines
}
printf("\nsecond : \n"); // separates the printings
for(int i;i<1001;i++)
{
for(int j;j<14;j++)
{
printf("%c",number[i][j]); //supposed to print each charac stored (doesnt work)
}
}
tf=clock();
printf("\n execution time : %f secondes",(tf-td)/CLOCKS_PER_SEC); //display execution time
return 0;
}
there are no warnings so i dont know what to do :/
The way you copy the substrings is broken:
while(fgets(str,line,pf)!= NULL)
{
printf("%s", str);
number[line][size_num]=str[line]; // here i want number to copy the 13 first characters
//of each 1000 lines
}
First of all, you always assign to number[1000][13] which is illegal as number only has 1000 rows, i.e. maximum index is 999. Also each row only has 13 elements making 12 the maximum index.
Same out of bounds access happens for str.
Then you do not have any counter indicating in which element of your array you want to copy the string.
Finally, strings cannot be copied by a simple assignment. You need to use strcpy or strncpy.
This loop should look like that:
int row = 0;
while(fgets(str,line,pf)!= NULL)
{
printf("%s", str);
strncpy(number[row], &str[0], size_num);
number[row][size_num-1] = 0; // Don't forget to terminate the string!
// Add copying the other parts here as well...
row++;
}
Then you also have a problem with printing the content:
for(int i;i<1001;i++)
{
for(int j;j<14;j++)
{
printf("%c",numero[i][j]); //supposed to print each charac stored (doesnt work)
}
}
Again, you have out of bounds accesses.
And you print all possible lines even if the file only contains a few lines.
Also you do not even initialize your loop counters to 0.
Do this instead:
for(int i = 0; i<row;i++)
{
#if 0
// use this part if you really want to print char by char...
for(int j = 0; j<size_num; j++)
{
printf("%c",numero[i][j]); //supposed to print each charac stored (doesnt work)
}
#else
// Use this if you want to print the string at once.
printf("%s\n",numero[i]);
#endif
}

How to read strings from stdin into a two-dimensional array in c programming using scanf() and while loop?

I'm writing a c code to read strings from stdin with scanf() and while loop (into a two-dimensional char array). My strategy is to use an input array to temporarily store each string and then assign it to a preword array (fixed sized). However, my strategy failed and all strings stored in my arrays are the same (the last string input). How to fix it?
I used a fgets() and it works find. However, I cannot use it to deal with a new line of strings (from stdin). My fgets() reads only the first line and that's why I turn to scanf and while loop.
#include<stdio.h>
#include<stdlib.h>
#define MAX 1000
#define size 50
int main ()
{
int count = 0;
char input[size];
char * preword[MAX];
while (scanf("%s",input)!= EOF){
preword[count] = input;
printf("preword[%d] is %s\n",count,preword[count]);
count++;
}
printf("the count is %d\n",count);
for (int i = 0; i < count; i++){
printf("preword[%d] is %s\n",i,preword[i]);
}
return 0;
}
I expect my input arrays from stdin will be stored in a two-dimensional char array. Below is the output in terminal after compilation. My input is a txt file, in which I have
hello world
I am a hero
It turns out that all strings stored in the two-d array are the last word.
preword[0] is hello
preword[1] is world
preword[2] is I
preword[3] is am
preword[4] is a
preword[5] is hero
the count is 6
preword[0] is hero
preword[1] is hero
preword[2] is hero
preword[3] is hero
preword[4] is hero
preword[5] is hero
Firstly here
char * preword[MAX];
preword is array of character pointer i.e each element is a char pointer & when you are doing like
preword[count] = input;
as #paddy pointed its copies input in every element of preword and it's the same pointer since you haven't allocated memory for preword[count], correct way is to allocate memory for each pointer and then copy.
Also use fgets() instead of scanf() here. For e.g
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 1000
#define size 50
int main (void)
{
int count = 0;
char input[size] = {0};
char * preword[MAX] = {0};
size_t retStrCspn = 0;
while (fgets(input, size, stdin) != NULL){
/* remove trailing new line if its stored at end of buffer by fgets() */
input[retStrCspn = strcspn(input, "\n")] = 0; /* remove the trailing & use the return value for allocating memory purpose \n */
preword[count] = malloc(retStrCspn + 1); /* Allocate memory for each pointer elements */
if(preword[count] != NULL) {
memcpy (preword[count], input, retStrCspn + 1); /* copy input buffer into each different memory location */
printf("preword[%d] is %s\n",count,preword[count]);
count++;
}
else {
/* #TODO malloc erro handling */
}
}
printf("the count is %d\n",count);
for (int i = 0; i < count && preword[i] != NULL; i++){
printf("preword[%d] is %s\n",i,preword[i]);
free(preword[count]); /* free dynamically allocated memory here*/
}
return 0;
}

How to read in a file, then place each struct within the file into an array?

I need to read in a file, and then assign each struct-sized amount of characters to a part of a struct array.
So, the first thirty characters would be first, second thirty characters would be last, and the 9 characters after that would be the ssn. This would be the first student in the array. The second student would begin after the 69th character, the third student would begin after the 138th character, and so on.
In the file, there would be something along the lines of:
john\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0smith\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0123456789jack\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0myers\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0987654321
Which would convert to:
allStudents[0].first = john
allStudents[0].last = smith
allStudents[0].ssn = 123456789
allStudents[1].first = jack
allStudents[1].last = myers
allStudents[1].ssn = 987654321
Here's the current set-up:
struct student allStudents[1000];
struct student {
char first[30];
char last[30];
char ssn[9];
};
void findStudents() {
int i;
FILE *fp;
char *temp;
int counter = 0;
int counter2 = 0;
fp = fopen("students.db","rt");
while( ( temp[counter2] = fgetc(fp) ) != EOF )
{
for (i = 0 ; i < 30 ; i++) {
strcat(allStudents[counter].first, temp);
counter2++;
}
for (i = 0 ; i < 30 ; i++) {
strcat(allStudents[counter].last, temp);
counter2++;
}
for (i = 0 ; i < 9 ; i++) {
strcat(allStudents[counter].ssn, temp);
counter2++;
}
counter++;
}
fclose(fp);
}
As many mentioned in comments, there are multiple problems there, starting from not allocating memory for char *temp to using char array of length 9 for storing 9 characters long number, leaving no room for terminating character.
Trying to make as little changes as possible, I would change ssn size in your structure from 9 to 10 so terminating character gets stored. Keep in mind that you could have used integer to store that data in there and it would be more efficient in terms of memory storage.
One other thing I would like to point out is your struct student allStudents[1000] array. You allocate immediately 1000 * sizeof(struct) bytes even if you have only 2 records in your database. Better approach would be using a linked list perhaps. Or just having an array of struct pointers( struct student *allStudents[1000] ) which would initially take much less memory, but you would have to allocate memory for every new struct.
I am assuming you're not allowed to change your students.db file, but we still need to add that terminating character, so there will be 69bytes in a file for a single record and 70 bytes in a structure. If you are allowed, I suggest you to change it.
struct student {
// max allowed first and last name length should be 29 to ensure a space for terminating character
char first[30];
char last[30];
char ssn[10];
}
struct student allStudents[1000];
void findStudents() {
int counter = 0;
// if you want to just read the file use "r" mode, if you're writing in it you can use "r+" or "w+", but there is no "rt" as far as I know
FILE *fp = fopen("students.db", "r");
// you should always check if file is opened
if(fp == NULL) {
printf("File not opened");
return;
}
// allocate memory where you will store a single record read from a file
// note -1 since your struct is now 70bytes large and a record in file is 69
// and for that reason we are using calloc instead of malloc, since calloc fills allocated memory with zero
char *temp = (char*) calloc(1, sizeof(struct student) - 1);
// instead of using fgetc for reading a single character, it's better to use fread here
// fread returns number of elements successfully read which should be 69 if everything is alright
while( ( fread(temp, 1, sizeof(struct student) - 1, fp) ) == sizeof(struct student) - 1 ) {
// copy the content we read into the structure
// we copy only 69 bytes here, leaving the last byte of structure untouched
// and it will be 0x00 (terminating character for your ssn)
memcpy(&allStudents[counter], temp, sizeof(struct student) - 1);
counter++;
}
// free the allocated memory and close the file since you won't be using them anymore
free(temp);
fclose(fp);
}
I would also suggest you to perhaps return the number of read entries from your student.db database.
I wrote this code in an assumption you cannot change student.db's file structure, but if you are allowed, please do consider mentioned suggestions.

How should I fix this interesting getdelim / getline (dynamic memory allocation) bug?

I have this C assignment I am a bit struggling at this specific point. I have some background in C, but pointers and dynamic memory management still elude me very much.
The assignment asks us to write a program which would simulate the behaviour of the "uniq" command / filter in UNIX.
But the problem I am having is with the C library functions getline or getdelim (we need to use those functions according to the implementation specifications).
According to the specification, the user input might contain arbitrary amount of lines and each line might be of arbitrary length (unknown at compile-time).
The problem is, the following line for the while-loop
while (cap = getdelim(stream.linesArray, size, '\n', stdin))
compiles and "works" somehow when I leave it like that. What I mean by this is that, when I execute the program, I enter arbitrary amount of lines of arbitrary length per each line and the program does not crash - but it keeps looping unless I stop the program execution (whether the lines are correctly stored in " char **linesArray; " are a different story I am not sure about.
I would like to be able to do is something like
while ((cap = getdelim(stream.linesArray, size, '\n', stdin)) && (cap != -1))
so that when getdelim does not read any characters at some line (besides EOF or \n) - aka the very first time when user enters an empty line -, the program would stop taking more lines from stdin.
(and then print the lines that were stored in stream.linesArray by getdelim).
The problem is, when I execute the program if I make the change I mentioned above, the program gives me "Segmentation Fault" and frankly I don't know why and how should I fix this (I have tried to do something about it so many times to no avail).
For reference:
https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html
https://en.cppreference.com/w/c/experimental/dynamic/getline
http://man7.org/linux/man-pages/man3/getline.3.html
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_SIZE 20
typedef unsigned long long int ull_int;
typedef struct uniqStream
{
char **linesArray;
ull_int lineIndex;
} uniq;
int main()
{
uniq stream = { malloc(DEFAULT_SIZE * sizeof(char)), 0 };
ull_int cap, i = 0;
size_t *size = 0;
while ((cap = getdelim(stream.linesArray, size, '\n', stdin))) //&& (cap != -1))
{
stream.lineIndex = i;
//if (cap == -1) { break; }
//print("%s", stream.linesArray[i]);
++i;
if (i == sizeof(stream.linesArray))
{
stream.linesArray = realloc(stream.linesArray, (2 * sizeof(stream.linesArray)));
}
}
ull_int j;
for (j = 0; j < i; ++j)
{
printf("%s\n", stream.linesArray[j]);
}
free(stream.linesArray);
return 0;
}
Ok, so the intent is clear - use getdelim to store the lines inside an array. getline itself uses dynamic allocation. The manual is quite clear about it:
getline() reads an entire line from stream, storing the address of the
buffer containing the text into *lineptr. The buffer is
null-terminated and includes the newline character, if one was found.
The getline() "stores the address of the buffer into *lineptr". So lineptr has to be a valid pointer to a char * variable (read that twice).
*lineptr and *n will be updated
to reflect the buffer address and allocated size respectively.
Also n needs to be a valid(!) pointer to a size_t variable, so the function can update it.
Also note that the lineptr buffer:
This buffer should be freed by the user program even if getline() failed.
So what do we do? We need to have an array of pointers to an array of strings. Because I don't like becoming a three star programmer, I use structs. I somewhat modified your code a bit, added some checks. You have the excuse me, I don't like typedefs, so I don't use them. Renamed the uniq to struct lines_s:
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
struct line_s {
char *line;
size_t len;
};
struct lines_s {
struct line_s *lines;
size_t cnt;
};
int main() {
struct lines_s lines = { NULL, 0 };
// loop breaks on error of feof(stdin)
while (1) {
char *line = NULL;
size_t size = 0;
// we pass a pointer to a `char*` variable
// and a pointer to `size_t` variable
// `getdelim` will update the variables inside it
// the initial values are NULL and 0
ssize_t ret = getdelim(&line, &size, '\n', stdin);
if (ret < 0) {
// check for EOF
if (feof(stdin)) {
// EOF found - break
break;
}
fprintf(stderr, "getdelim error %zd!\n", ret);
abort();
}
// new line was read - add it to out container "lines"
// always handle realloc separately
void *ptr = realloc(lines.lines, sizeof(*lines.lines) * (lines.cnt + 1));
if (ptr == NULL) {
// note that lines.lines is still a valid pointer here
fprintf(stderr, "Out of memory\n");
abort();
}
lines.lines = ptr;
lines.lines[lines.cnt].line = line;
lines.lines[lines.cnt].len = size;
lines.cnt += 1;
// break if the line is "stop"
if (strcmp("stop\n", lines.lines[lines.cnt - 1].line) == 0) {
break;
}
}
// iterate over lines
for (size_t i = 0; i < lines.cnt; ++i) {
// note that the line has a newline in it
// so no additional is needed in this printf
printf("line %zu is %s", i, lines.lines[i].line);
}
// getdelim returns dynamically allocated strings
// we need to free them
for (size_t i = 0; i < lines.cnt; ++i) {
free(lines.lines[i].line);
}
free(lines.lines);
}
For such input:
line1 line1
line2 line2
stop
will output:
line 0 is line1 line1
line 1 is line2 line2
line 2 is stop
Tested on onlinegdb.
Notes:
if (i == sizeof(stream.linesArray)) sizeof does not magically store the size of an array. sizeof(stream.linesArray) is just sizeof(char**) is just a sizeof of a pointer. It's usually 4 or 8 bytes, depending if on the 32bit or 64bit architecture.
uniq stream = { malloc(DEFAULT_SIZE * sizeof(char)), - stream.linesArray is a char** variable. So if you want to have an array of pointers to char, you should allocate the memory for pointers malloc(DEFAULT_SIZE * sizeof(char*)).
typedef unsigned long long int ull_int; The size_t type if the type to represent array size or sizeof(variable). The ssize_t is sometimes used in posix api to return the size and an error status. Use those variables, no need to type unsigned long long.
ull_int cap cap = getdelim - cap is unsigned, it will never be cap != 1.

fscanf usage in c - Values not saving properly

I have a small sample program to illustrate my issue below: I have a simple text file with three words (each in a new line) which fscanf reads, assigns to a temporary variable and then transfers to a string array. Yet, the values do not seem to transfer to the array. Also, when I remove the comment // from the second printf in the while loop I get a seg fault.
I'm fairly new to C, so only now learning the usage of these functions! Thanks in advance for assistance!
#include <stdio.h>
#include <string.h>
int main (int argc, char* argv[])
{
char* words[15];
char tmp[45];
int i = 0;
FILE* fp = fopen("small", "r");
while (fscanf(fp, "%s", tmp) == 1)
{
printf("%s\n", tmp);
words[i] = tmp;
i++;
//printf("%s ", words[i]);
}
printf("\n");
printf("Words 0 = %s\n", words[0]);
printf("Words 2 = %s\n", words[1]);
printf("Words 3 = %s\n", words[2]);
fclose(fp);
}
Output
pears
apples
zipper
Words 0 = zipper
Words 2 = zipper
Words 3 = zipper
In your code, words[i] = tmp; is not the way to store each input to the words array. That only stores the base address of the tmp array into each words[i] and later, while printing, it actually prints the latest content of the tmp on every iteration.
If you want to get the contents of the tmp array into each words[i], you need to either
Allocate memory to each words[i] and use strcpy()
Use strdup() and assign that to words[i].
In either of cases, you have to free() the allocated memories before exit.
I had the same problem in the past.
The problem is that when you read from the file, the word is kept in the buffer, and then you store it to the variable temp.
The thing is that when you read the next word, the contents of the buffer change. And this affects the previous call too!
So you read "pears", you print "pears" and words[0] = "pears"
Then you read "apples", you print apples and words[1] = "apples". BUT ALSO words[0] = "apples" now!!
And so on...
What you need to do is before reading the file, to allocate memory with malloc for every words[i] and get it equal to "".
e.g. words[0] = "" etc.
Then when you start reading the file, you should use the strcpy() function for temp and words[i]. This will solve your problem.
I tried to answer this as simply as i could because in the past that issue troubled me and confused me a lot.
The first important problem with your code is this line
char* words[15];
It gives you an array of 15 char pointers (char*). That is not the same as an array of 15 strings. There are no memory for storing the strings.
To get memory for storing the strings, you can do:
char words[15][45];
// ^ ^^
// no * memory for each of the 15 strings
Now you have memory for 15 strings. Each string can be up to 44 chars.
With this change you don't need the tmpvariable - just read directly into words. Something like:
#include <stdio.h>
#include <string.h>
int main (int argc, char* argv[])
{
char words[15][45];
int i = 0;
FILE* fp = fopen("small", "r");
if (!fp)
{
printf("no such file\n");
return 0;
}
while ((i < 15) && (fscanf(fp, "%44s", words[i]) == 1))
{ // ^^^^^^^^ is the same as &words[i][0]
i++;
}
printf("\n");
int t;
for (t = 0; t < i; ++t)
{
printf("Words %d = %s\n", t, words[t]);
}
fclose(fp);
return 0;
}
Some other important changes added:
1) After fopen you must check for NULL
2) For scanf with %s always give a max size (i.e. %44s) so there can't be buffer overflow
3) Make sure to stop the while when you have read 15 strings (to prevent buffer overflow)
4) Only print as many strings as you have read in
Finally I added return 0 to the end of main

Resources