I'm working on a project using C and for the project I must read in a text file and store each word into an array. I also have to remove the punctuation off the words, so I need to use a 2-Dimensional array in order to edit the words. I am having trouble figuring out how to get the words in the 2-D array it self. This is what I have done so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 1001
#define LINES 81
int main(void) {
int stringSize;
int i =0;
char *x[MAX][LINES];
char str[MAX];
char y[MAX];
FILE *fp;
fp = fopen("TwoCitiesStory.txt","r");
if(fp == NULL) {
printf("Cannot open file.\n");
exit(1);
}
while(!feof(fp)) {
for(i=0;i<MAX;i++){
fscanf(fp,"%s",x[i][LINES]);
}
}
return 0;
}
The following line
char *x[MAX][LINES];
declared a 2D array of pointers. What you need is just a 2D array of characters.
char x[MAX][LINES];
The code for reading the words can be simplified to:
while( i < MAX && fscanf(fp, "%80s", x[i]) == 1 )
{
++i;
}
Read the whole line using fgets()
Store the read line into the 2D array
The whole code looks like
char x[row][col];
char buf[300];
int i=0,j=0;
memset(x,0,sizeof(x));
while(fgets(buf,sizeof(buf),fp))
{
size_t n = strlen(buf);
if(n>0 && buf[n-1] == '\n')
buf[n-1] = '\0';
if(i>= row && n> col)
break;
strcpy(x[i],buf);
i++;
}
Edits:
If you need each word separately in the array.
buf is being used to read the whole line.
strtok() is used to break the line into words with space as delimiter.
Then store each word in each row.
size_t n;
while(fgets(buf,sizeof(buf),fp))
{
char *p = strtok(buf," ");
while( p != NULL)
{
n = strlen(p);
if(i>= row && n> col)
break;
strcpy(x[i],p);
i++;
p = strtok(NULL," ");
}
}
If you want to print out the array go for
int i;
for(i=0;i<row;i++)
printf("%s\n",x[i]);
Why feof() is wrong
Related
I want to create a program in C that takes an arbitrary number of lines of arbitrary length as input and then prints to console the last line that was inputted. For example:
input:
hi
my name is
david
output: david
I figured the best way to do this would be to have a loop that takes each line as input and stores it in a char array, so at the end of the loop the last line ends up being what is stored in the char array and we can just print that.
I have only had one lecture in C so far so I think I just keep setting things up wrong with my Java/C++ mindset since I have more experience in those languages.
Here is what I have so far but I know that it's nowhere near correct:
#include <stdio.h>
int main()
{
printf("Enter some lines of strings: \n");
char line[50];
for(int i = 0; i < 10; i++){
line = getline(); //I know this is inproper syntax but I want to do something like this
}
printf("%s",line);
}
I also have i < 10 in the loop because I don't know how to find the total number of lines in the input which, would be the proper amount of times to loop this. Also, the input is being put in all at once from the
./program < test.txt
command in Unix shell, where test.txt has the input.
Use fgets():
while (fgets(line, sizeof line, stdin)) {
// don't need to do anything here
}
printf("%s", line);
You don't need a limit on the number of iterations. At the end of the file, fgets() returns NULL and doesn't modify the buffer, so line will still hold the last line that was read.
I'm assuming you know the maximum length of the input line.
This one here will surely do the job for you
static char *getLine( char * const b , size_t bsz ) {
return fgets(b, bsz, stdin) );
}
But remember fgets also puts a '\n' character at the end of buffer so perhaps something like this
static char *getLine( char * const b , size_t bsz ) {
if( fgets(b, bsz, stdin) ){
/* Optional code to strip NextLine */
size_t size = strlen(b);
if( size > 0 && b[size-1] == '\n' ) {
b[--size] = '\0';
}
/* End of Optional Code */
return b;
}
return NULL;
}
and your code needs to be altered a bit while calling the getline
#define BUF_SIZE 256
char line[BUF_SIZE];
for(int i = 0; i < 10; i++){
if( getLine(line, BUF_SIZE ) ) {
fprintf(stdout, "line : '%s'\n", line);
}
}
Now it is how ever quite possible to create function like
char *getLine();
but then one needs to define the behavior of that function for instance if the function getLine() allocates memory dynamically then you probably need use a free to de-allocate the pointer returned by getLine()
in which case the function may look like
char *getLine( size_t bsz ) {
char *b = malloc( bsz );
if( b && fgets(b, bsz, stdin) ){
return b;
}
return NULL;
}
depending on how small your function is you can entertain thoughts about making it inline perhaps that's a little off topic for now.
In order to have dynamic number of input of dynamic length, you have to keep on reallocating your buffer when the input is of greater length. In order to store the last line, you have to take another pointer to keep track of it and to stop the input from the terminal you have to press EOF key(ctrl+k). This should do your job.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_last_line(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
char *str, *last_str = NULL;
int ch;
size_t len = 0, last_len = 0;
str = realloc(NULL, sizeof(char)*size);//size is start size
if(!str)return str;
while(ch=fgetc(fp)){
if(ch == EOF){
break;
}
if(ch == '\n'){
str[len]='\0';
last_len = len;
last_str = realloc(last_str,sizeof(char)*last_len);
last_str[last_len]='\0';
//storing the last line
memcpy(last_str,str,sizeof(char)*last_len);
str = realloc(NULL, sizeof(char)*size);//size is start size
len = 0;
}
else {
str[len++]=ch;
if(len==size){
str = realloc(str, sizeof(char)*(size+=16));
if(!str)return str;
}
}
}
free(str);
return last_str;
}
int main(void){
char *m;
printf("input strings : ");
m = get_last_line(stdin, 10);
printf("last string :");
printf("%s\n", m);
free(m);
return 0;
}
I'm trying to open a file, read the content line by line (excluding the empty lines) and store all these lines in an array, but seems I cannot come to the solution.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char buffer[500];
FILE *fp;
int lineno = 0;
int n;
char topics[lineno];
if ((fp = fopen("abc.txt","r")) == NULL){
printf("Could not open abc.txt\n");
return(1);
}
while (!feof(fp))
{
// read in the line and make sure it was successful
if (fgets(buffer,500,fp) != NULL){
if(buffer[0] == '\n'){
}
else{
strncpy(topics[lineno],buffer, 50);
printf("%d: %s",lineno, topics[lineno]);
lineno++;
printf("%d: %s",lineno, buffer);
}
}
}
return(0);
}
Considering "abc.txt" contains four lines (the third one is empty) like the following:
ab
2
4
I have been trying several ways but all I'm getting now is segmentation fault.
It is mostly because you are trying to store the read line in a 0 length array
int lineno = 0;
int n;
char topics[lineno]; //lineno is 0 here
There are more mistakes in your program after you correct the above mentioned one.
strncpy() needs a char* as its first parameter, and you are passing it a char.
If you want to store all the lines, in a manner such that array[0] is the first line, array[1] is the next one, then you would need an `array of char pointers.
Something like this
char* topics[100];
.
.
.
if (fgets(buffer,500,fp) != NULL){
if(buffer[0] == '\n'){
}
else{
topics[lineno] = malloc(128);
strncpy(topics[lineno],buffer, 50);
printf("%d: %s",lineno, topics[lineno]);
lineno++;
printf("%d: %s",lineno, buffer);
}
NOTE:
Use the standard definition of main()
int main(void) //if no command line arguments.
Bonus
Since you have accidentally stepped onto 0 length array, do read about it here.
This declaration of a variable length array
int lineno = 0;
char topics[lineno];
is invalid because the size of the array may not be equal to 0 and does not make sense in the context of the program/
You could dynamically allocate an array of pojnters to char that is of type char * and reallocate it each time when a new record is added.
For example
int lineno = 0;
int n;
char **topics = NULL;
//...
char **tmp = realloc( topics, ( lineno + 1 ) * sizeof( char * ) );
if ( tmp != NULL )
{
topics = tmp;
topics[lineno] = malloc( 50 * sizeof( char ) );
//... copy the string and so on
++lineno;
}
I have a problem, my program in C have to find words with N letters, count them and sort them in lexicographical order and save them to an another file. I've done the first 2 things, but sorting them and save to the file doesn't work. It saves only the last word to the second file... do you have any idea why?
this is my code:
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include <stddef.h>
#include <string.h>
int main()
{
FILE *r, *fp;
char ch[100];
int n,i,j,x=0;
r=fopen("text.txt","r");
fgets(ch, 100, r);
char *s = ch;
char *p = s;
printf("Give the length of word: ");
scanf("%d",&n);
printf("\n\nWords with %d letters: \n\n",n);
while (*p) {
char *start;
int len;
while (*p && isspace(*p))
++p;
start = p;
while (*p && !isspace(*p))
++p;
len = p - start;
fp=fopen("text2.txt","w");
if (len == n) {
printf("%.*s\n", len, start);
x++;
fprintf(fp,"%.*s",len, start);
}
}
printf("\nNumber of words: %d ",x);
fclose(fp);
getch();
fclose(r);
}
my input file:
hi my name is Zsolt this program if for displaying words with N letters count them and sort them alphabeticaly a save them to an another file
It is because you open text2.txt in every iteration of your while loop. And what is more, you open it with mode "w" which if you look at the documentation states:
write: Create an empty file for output operations. If a file with the same name already exists, its contents are discarded and the file is treated as a new empty file.
So what is happening is, at every iteration, you open the file, discarding whatever was there before, (which after the first iteration would be a file with a single word in it).
Instead you should open it before you enter the while loop.
Additionally, you stated that you wanted to sort the words you found in lexicographical order before you wrote them to the new file. If your code had written the words as you had intended, then they would be in the order they appeared in the original file, not lexicographic order. You are better off saving the pointers to the n-length words in an array, sorting that array, and then writing it all in one go to your output file.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_WORDS 100
int
qstrcmp(const void *a, const void *b)
{
const char
*s = *(const char **)a,
*t = *(const char **)b;
return strcmp(s, t);
}
int
main()
{
FILE *input, *output;
input = fopen("text.txt", "r");
// Get length to filter by
unsigned long n;
scanf("%lu", &n);
char *words[MAX_WORDS];
int i = 0;
// Find words of correct length
char buf[100];
while (fscanf(input, "%99s", buf) != EOF) {
// Protect from buffer overflow
if (i >= MAX_WORDS) {
printf("Too many words!");
break;
}
if (strlen(buf) == n) {
words[i++] = strncpy(malloc(n+1), buf, n+1);
}
}
fclose(input);
// Sort in lexicographical order.
qsort(words, i, sizeof(char *), qstrcmp);
// Write to output
output = fopen("text2.txt", "w");
for (int j = 0; j < i; ++j) {
fprintf(output, "%s\n", words[j]);
}
fclose(output);
// Print number found.
printf("Found %d word%s of length %lu.\n", i, i == 1 ? "": "s", n);
return 0;
}
Implementation Notes
Sorting is achieved with qsort from "stdlib.h".
Pay attention to buffer overflows! In this case I just bail, but alternatively, you could re-allocate the memory for the words array.
Remember to copy the null-byte over when saving the word.
qsort passes references to the array elements it's sorting to its comparator function, so it will pass values of type const char **, this is why we need to use the qstrcmp wrapper function.
I'm new to C (coming from Java) and naturally that poses some difficulties. I would like to write just a short program that reads in char-Arrays from stdin and stores the individual strings in an array. After reading in the strings I just want to have them printed out, but that's when it gets really confusing for me.
Here's my code:
#include <stdlib.h>
#include <stdio.h>
int main(){
char **stringarray[2];
char buffer[5];
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
char *tmp = buffer;
stringarray[i] = &tmp;
i++;
}
for(int i = 0; i < 2; i++){
printf("%s\n", &stringarray[i]);
}
return 0;
}
The first part does in fact compiles (i.e. the part before the print out). I understand that my stringArray has to be an array of char pointers, because that's what a char array basically is in c. It's a pointer to the first character. At first I just wrote
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
stringarray[i] = buffer;
i++;
}
which also compiled, but of course then I have one pointer that points to buffer, which will only save the last string that has been read.
What do I have to do that I can store a simple array of strings?
I suggest you change your code as following.
#include <stdlib.h>
#include <stdio.h>
#include <string.h> /* to use strdup function */
int main(){
char *stringarray[2]; /* I don't understand why you use pointer to pointer than pointer, char **stringarray[2]; */
char buffer[6]; /* I suggest 6 than 5, because string has terminate byte in C */
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
stringarray[i] = strndup(buffer, 5);
i++;
}
for(int i = 0; i < 2; i++){
printf("%s\n", stringarray[i]); /* changed stringarray */
}
return 0;
}
char **stringarray[2]; is like char ***stringarray because an array is like a pointer to the first value of the array.
printf wants a char* and &stringarray[i] is a char**
if a string is an array then an array of strings is an array of array.
So the code is :
int main()
{
char stringarray[2][5];//array of (array of char)
char buffer[5];
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL)
{
strcpy(stringarray[i],buffer); //copies the buffer into the string array
i++;
}
for(i = 0; i < 2; i++)
{
printf("%s\n", stringarray[i]);
}
return 0;
}
If you didn't want to use buffer you could just writte :
while( i < 2 && fgets(stringarray[i], 5, stdin) != NULL)
{
i++;
}
Note that you get 5 characters, the last one will be the NUL terminator \0. And because you have to press enter to validate, the one before \0 will be Line Feed\n. And you will only have 3 characters you really wanted.
You can do it using dynamic allocation technique as below .
#include<stdio.h>
#include<malloc.h>
#include <stdlib.h>
int main()
{
int num;
int len=0;
int i;
printf("Enter the number of elements to be entered ");
scanf("%d",&num);
//Allocate memory for the array of strings
char **var=(char **)malloc(num * sizeof(char *));
for(i=0;i<num;i++)
{
printf("Enter the string : ");
//get strings using getline
getline(&var[i],&len,stdin);
}
for(i=0;i<num;i++)
{
printf("String %d : %s \n",i,var[i]);
}
free(var);
}
I want to store the following lines from an input file into a 3D Array (excluding the first line.) The first line represents the number of following lines.
3
4 9368 86 843 23224
4 7323 2 2665 2665
8447 47 843 5278 8378 2273
My problem is if I use fscanf, there is no way to tell when there is a newline. Therefore I can't stop scanning and go to the next index in the outermost array. If I use fgets and sscanf, I can only read in the first string of each line (in this case, 4 then 4 then 8447.)
That is because fgets processes an entire line as one string (1D Array,) when I want each line to be processed as a 2D array, and then each stored in an outermost array, resulting in a 3D array.
How can I solve this problem?
You can use sscanf() combined with fgets() to parse one number at a time. You can do it by advancing a pointer into your string as you parse each number.
while (fgets(buf, sizeof(buf), infile) != 0) {
const char *p = buf;
size_t len = strlen(buf);
int val;
int n;
while (sscanf(p, "%d%n", &val, &n) == 1) {
/*...do something with val */
p += n;
if (p >= buf+len) break;
}
}
The %n directive provides the number of bytes consumed thus far in the scan.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void){
char array[16][16][16];
char line[256];
FILE *fp = fopen("data.txt", "r");
fgets(line, sizeof(line), fp);
int row = atoi(line);
int i;
for(i = 0;i<row;++i){
int col = 0;
char *p;
fgets(line, sizeof(line), fp);
for(p = strtok(line, " \t\n");p;p=strtok(NULL, " \t\n")){
strcpy(array[i][col++], p);
}
array[i][col][0] = '\0';
}
fclose(fp);
{//check
for(int i=0;i<row;++i){
for(int j=0;array[i][j][0];++j)
printf("%s ", array[i][j]);
printf("\n");
}
}
return 0;
}