string array of varying length - c

Im writing a C code to read a file line by line which contains alphabets, CR,LF,'\0'. Below is my attached code sample. I want to store only alphabets from each line to an array such that the numbers of rows in the array equals no of lines in the file and column should be of varying length(depends on the number of character in i-th line).
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *buffer[100];
char temp[128];
int c,i=0,j=0;
int pos=0;
FILE *file;
file = fopen("input", "r");
if (file) {
while ((c = getc(file)) != EOF){
if ((c>=65 && c<=90) || (c>=97 && c<=122))
temp[pos++]=c;
else if(pos>1) {
temp[pos]='\0';
buffer[i]=temp;
printf ("%s\n",temp);
i++;
pos=0;
}
}
}
fclose(file);
while (j<i){
printf("%s\n",buffer[j]);
j++;
}
}
If i run my above code, all my buffer[j] contains same string.
Can anyone help me out in figuring what was wrong in the code.

buffer[] is an array of pointers, in your while loop you are pointing each of them to your array temp[]
buffer[i]=temp; // assign the address of temp to buffer[i]
Then you're changing the content of your temp[] array, but the address is always the same.
If you want to store the data from temp into each position in buffer[] you need to allocate memory and copy the data over there. More like:
buffer[i]=malloc(strlen(temp) + 1);
strcpy(buffer[i], temp);

Related

Troubles with pointers when reading from a txt file

Im trying to print out the strings from a txt file in order.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
// Check for command line args
if (argc != 2)
{
printf("Usage: ./read infile\n");
return 1;
}
// Create buffer to read into
char buffer[7];
// Create array to store plate numbers
char *plates[8];
FILE *infile = fopen(argv[1], "r");
int idx = 0;
while (fread(buffer, 1, 7, infile) == 7)
{
char buffer2[7];
// Replace '\n' with '\0'
buffer[6] = '\0';
strcpy(buffer2, buffer);
// Save plate number in array
plates[idx] = buffer2;
idx++;
}
for (int i = 0; i < 8; i++)
{
printf("%s\n", plates[i]);
}
}
The pasted code just writes one and the same string over and over again, and I cant for the life of me figure out what Im doing wrong. When I debug the "while" method, I see that the buffer updates keep overwriting every entry to the plates array.
In this for loop
while (fread(buffer, 1, 7, infile) == 7)
{
char buffer2[7];
// Replace '\n' with '\0'
buffer[6] = '\0';
strcpy(buffer2, buffer);
// Save plate number in array
plates[idx] = buffer2;
idx++;
}
you declared a local array with automatic storage duration
char buffer2[7];
that will not be alive after exiting the loop. And all elements of the array plates are set by the address of the first element of the array buffer2. That is within the for loop they all point to the same extent of memory.
After exiting the loop the pointers will be invalid.
You need to allocate character arrays dynamically and their addresses to assign to the elements of the array plates.
Also pay attention to that the function fread does not read a string. So this statement
buffer[6] = '\0';
overwrites the last character stored in the array.
Using dynamic allocation should fix your problem. You could try something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
// Check for command line args
if (argc != 2)
{
printf("Usage: ./read infile\n");
return 1;
}
// Create buffer to read into
char buffer[7];
// Create array to store plate numbers
char *plates[8];
FILE *infile = fopen(argv[1], "r");
int idx = 0;
while (fread(buffer, 1, 7, infile) == 7)
{
// Replace '\n' with '\0'
buffer[6] = '\0';
// Save plate number in array
plates[idx] = malloc(sizeof(buffer));
strcpy(plates[idx++], buffer);
}
for (int i = 0; i < 8; i++)
{
printf("%s\n", plates[i]);
free(plates[i];
}
}
The pasted code just writes one and the same string over and over again, and I cant for the life of me figure out what Im doing wrong. When I debug the "while" method, I see that the buffer updates keep overwriting every entry to the plates array.
#Vlad from Moscow gave you an explanation for this:
that will not be alive after exiting the loop. And all elements of the array plates are set by the address of the first element of the array buffer2. That is within the for loop they all point to the same extent of memory.
"Im trying to print out the strings from a txt file in order."
As noted in comments fread() as used in your implementation is not the best way to read lines in a text file.
Answering these 2 questions (at minimum the first one) will provide important values to help in declaring and initializing the right sized (and shaped) buffers for reading lines from a file...
What is the longest line in the file?
How many lines are in the file? (may be optional if not storing all lines)
The following example(s) can be accomplished knowing only the answer to the first question, but knowing the answer to the second would be useful if it was necessary for example to store all of the lines into an array of strings. (This is out of scope here as you did not list that as a requirement for your code)
Unless you are comfortable with making an assumption on the maximum line length, i.e. hard-coded...
char line[guessed_max_line_length] = {0};
...a run-time assessment to determine the length of the longest line in the file is necessary to size the buffer such that it can safely contain lines that will later be read from file. Once this assessment is done, use the length of the longest line to create a line buffer during run-time. (dynamically allocate memory):
char *line = malloc(max_length + 1);
memset(line, 0, max_length + 1);
Using these methods, (and providing the implementation linked above) your code can be simplified to the following adaptation....
//prototype to get max line length in file
size_t longestLine(FILE *fi);
int main(int argc, char *argv[])
{
// Check for command line args
if (argc != 2)
{
printf("Usage: ./read infile\n");
return 1;
}
FILE *infile = fopen(argv[1], "r");
if(infile)
{
size_t max_length = longestLine(infile); //see linked implemenation from above
rewind(infile);//suggest adding this line to longestLine() implementation.
char *line = malloc(max_length + 1);
if(line)
{
memset(line, 0, max_length + 1);
while(fgets(line, max_length, infile))
{
fputs(line, stdout);
//or alternatively
//printf("%s", line);
}
free(line);
}
fclose(infile);
}
return 0;
}

Understanding struct pointer in C EDIT: Improper use of feof()

I am having difficulty understanding why I am receiving an error with my C program. The main function makes a call to readFile() function which copies the contents of a text file to a 'Text' struct's 2D char array, then returns the struct. When I iterate through the struct array, I print the contents of the array without issue. But, when attempting to use a pointer to the struct and print the contents of the array, it prints garbage in certain cases.
The contents of my text.txt file is:
Hello world.
Hello galaxy.
Hello universe.
Goodbye.
And, Here is the code:
#include <stdio.h>
#include <stdlib.h>
struct Text {
char array[10][50];
};
struct Text readFile(char*);
int main(int argc, char *argv[]) {
int i, j;
char * file = argv[1];
struct Text text = readFile(file); // init Text struct w/call to readFile
struct Text * ptr_text = &text; // declare and init a ptr to struct
// print contents of 2D text array
for (i=0; i<sizeof(text.array) / sizeof(text.array[0]); i++) {
for (j=0; j<sizeof(text.array[0]); j++) {
printf("%c", text.array[i][j]);
if (text.array[i][j] == '\n') {
break; // breaks inner for loop & goes to next column in array
}
}
}
// same logic, but, w/ using a pointer to reference struct's array
for (i=0; i<sizeof(ptr_text->array) / sizeof(ptr_text->array[0]); i++) {
for (j=0; j<sizeof(ptr_text->array[0]); j++) {
printf("%c", ptr_text->array[i][j]);
if (ptr_text->array[i][j] == '\n') {
break; // breaks inner for loop & goes to next column in array
}
}
}
return 0;
}
// readFile function definition--
// reads text file, asigns contents to a 'Text'
// struct with a char array and returns its ptr
struct Text readFile(char* file) {
FILE *fp = NULL;
int col = 0;
int row = 0;
char c;
// declare Text struct & init w/ null chars
struct Text t = {{'\0'}};
fp = fopen(file,"r");
if (fp == NULL) {
exit(99);
}
printf("Reading File: %s\n", file);
// while loop assigns chars from file to Text struct's 2D array
while (1) {
if (feof(fp)) {
break;
}
c = getc(fp);
t.array[row][col] = c;
// if newline char, increment to next row in array, reset col to 0
if (c == '\n') {
row++;
col = 0;
continue;
}
// else, increment column in array
col++;
}
fclose(fp);
return t; // return Text struct
}
Program Output:
[cabox#Centos7-2 c]$ ./read_file1.o ./text.txt
Reading File: ./text.txt
Hello world.
Hello galaxy.
Hello universe.
Goodbye.
�Hello world.
Hello galaxy.
Hello universe.
Goodbye.
�
From the above, you can see that there are invalid (memory errors?) symbols when attempting to print the contents of the struct's array by using a pointer. So, clearly it has to do with my lack of understanding/incorrect use of a pointer. Sorry if this is a duplicate, I searched a good while for an answer to no avail.
EDIT:
Turns out, this has nothing to do with pointers afterall. As mentioned, I clearly didn't understand the proper use of feof(). Along with the suggestions, I had to add the following lines to the nested print loops:
if (ptr_text->array[i][j] == '\0') {
break;
}
Making the complete code for printing the loop:
for (i=0; i<sizeof(ptr_text->array) / sizeof(ptr_text->array[0]); i++) {
for (j=0; j<sizeof(ptr_text->array[0]); j++) {
if (ptr_text->array[i][j] == '\0') {
break;
}
printf("%c", ptr_text->array[i][j]);
if (ptr_text->array[i][j] == '\n') {
break; // breaks inner for loop & goes to next column in array
}
}
}
This way, when a null character in the array is reached, the program will continue to break the print loop (ultimately until main terminates), without printing anything that was not originally copied to the array via the call to readFile().
Thanks all for the quick replies!
For starters instead of this declaration
char c;
you have to write
int c;
And this while loop
while (1) {
if (feof(fp)) {
break;
}
c = getc(fp);
//...
also tries to write the EOF value in your array.
You need to rewrite the condition like for example
while ( ( c = getc(fp) ) != EOF )
and though the array within the structure is zero initialized
struct Text t = {{'\0'}};
nevertheless it is better to append each line with the terminating zero character '\0' explicitly. This will make your code clearer.

C read file content into an array of strings

I need to load the contents of a file into two string arrays. I tried the following and it is not working.
file.txt contains 10 records and each record has two string values separated by whitespace.
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[12][20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
fptr = fopen("file.txt", "r");
char arr[20][20];
while (fgets(line, sizeof(line), fptr)) {
strcpy(arr[i],line);
i++;
}
tot=i;
for (int i=0; i<tot; i++) {
printf("first value %s",arr[i][0]);
printf("second value is %s",arr[i][1]);
printf("\n");
}
return 0;
}
If I understand correctly, you're trying to store data in a structure like:
{{"line1A", "line1B"}, {"line2A", "line2B"}, {"line3A", "line3B"}}
It looks like you need an array where each element consists of two arrays (strings), one for the first value and one for the second value on each line. If this is the case, you need a three dimensional array of chars.
In the example below I've declared arrayOfLines as array with 12 elements each of which has 2 arrays of chars (for your two values per line), with space for 20 chars in each string (NULL terminated char array)
There are some other problems with your code:
The first parameter for fgets() should be a char * - a pointer to a string buffer. Your code passes in a multi-dimensional array of chars.
Your while loop should continue until fgets returns NULL
You need to split each line into multiple strings
Check for buffer overruns when copying strings with strcpy()
In the example code I used strtok() delimited by a " " space character - you may need to play around with this - strtok can accept an array of chars to be used as a delimiter. In the example, I split the first string using the first space char, and the second string is delimited by the end of line.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
// Array for 12 lines, each with 2 strings, each string max 20 chars
// Adjust values as required.
char arrayOfLines[12][2][20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
fptr = fopen("file.txt", "r");
// char arr[20][20]; not needed
char line[20];
while(fgets(line, sizeof(line) / sizeof(line[0]), fptr) != NULL)
{
// Rudimentary error checking - if the string has no newline
// there wasn't enough space in line
if (strchr(line, '\n') == NULL) {
printf("Line too long...");
return EXIT_FAILURE;
}
// Split string into tokens
// NB: Check for buffer overruns when copying strings
char *ptr1 = strtok(line, " ");
strcpy(arrayOfLines[i][0], ptr1);
char *ptr2 = strtok(NULL, "\n");
strcpy(arrayOfLines[i][1], ptr2);
i++;
}
tot=i; // Unecessary - just use a different variable in your loop and use i as the upper bound
for (int i=0;i<tot;i++)
{
printf("first value %s\n", arrayOfLines[i][0]);
printf("second value is %s\n", arrayOfLines[i][1]);
printf("\n");
}
return 0;
}
printf("first value %s",arr[i][0]);
printf("second value is %s",arr[i][1]);
Basicly all you are doing is printing 2 chars from i word when you want to print full string you should do it like this: printf("%s",arr[i]); You said that value is separated by whitespace so when you are getting line from file you will save it to arr[i] (if first line in file contains "Hello World", your arr[0] will contain "Hello World") when you want to split it into 2 printf you need to print them char by char until space.
Edit: I reminded myself about function sscanf you can use it to get data from file array like you whould do it with keyboard input
You can use this to do that
Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
char line[12][20];
char arr[20][20];
FILE *fptr=NULL;
int i=0;
fptr = fopen("file.txt", "r");
if(!fptr){
printf("cant open file\n");
exit(1);
}
while(fgets(*line, sizeof(line), fptr)){
strncpy(arr[i],*line, sizeof(*line));
i++;
}
for (int j=0;j<i;j++){
printf("%s\n", arr[j]);
}
return 0;
}
Notes and changes I made on your code:
Check fptr as return value of open() if it's NULL decide what to do.
Remove unnecessary tot variable and use another index j in last for loop.
Use strncpy() as a better version of strcpy()
Correct way of print arr, printf("%s\n", arr[j]);
\n can be embed on first printf()

How to copy every n-th characters from one char array to another?

I have a program that reads file A and then copies the contents to file B.
I would like to write to file B every third character. I created a loop that rewrites every third item to a new char array. In file B I get strange characters. What am I doing wrong?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main ()
{
int i;
char full_string[100];
char reduce_string[100];
char file_name_for_read[128];
char file_name_for_save[128];
printf("Enter file name for read...\n");
scanf ("%s", file_name_for_read);
strcat(file_name_for_read,".txt");
FILE *fileA;
fileA=fopen(file_name_for_read,"r");
printf("Enter file name for save...\n");
scanf ("%s", file_name_for_save);
strcat(file_name_for_save,".txt");
FILE *fileB;
fileB=fopen(file_name_for_save,"w");
while(fgets(full_string, sizeof(full_string), fileA) !=NULL)
{
for(i = 2; i < 100; i+=3)
{
reduce_string[i-=2] = full_string[i+=1];
}
fprintf(fileB, "%s", reduce_string);
}
fclose(fileA);
fclose(fileB);
}
What am I doing wrong?
Several things. At minimum,
In your inner loop, you iterate over the full length of full_string, regardless of how many of those bytes were actually read from the file by the most recent fgets().
In your inner loop, you invoke undefined behavior because the expression reduce_string[i-=2] = full_string[i+=1] has two side effects on the value of i that are unsequenced relative to each other.
In that expression, i - 2 is anyway not the index you want except when i is 2, because you increment i by 3 at each iteration. You'll end up filling some positions and skipping others.
You do not add a null terminator at the end of the data copied into reduce_string.
Your strategy does not anyway result in copying every third character of the file; rather, it copies every third character of each line. These differ unless all the line lengths of the input files are multiples of 3.
reads file A and then copies the contents to file B. I would like to write to file B every third character.
If lines are not important,
seems simple to read 3 characters and write the 3rd one.
for(;;) {
fgetc(fileA);
fgetc(fileA);
int ch = fgetc(fileA);
if (ch == EOF) break;
fputc(ch, fileB);
}
or
int ch;
do {
fgetc(fileA);
fgetc(fileA);
ch = fgetc(fileA);
} while (ch != EOF && fputc(ch, fileB) != EOF);
The easiest way is to use a different index for each array, that way each can go at their own speed.
int i,x;
for(i = 0, x=0; i < 1000; i+=3, x++)
{
reduce_string[x] = full_string[i];
}
fprintf(fileB, "%s", reduce_string);
Check this code out. In your code, you have reduce_string[i-=2] = full_string[i+=1]; — I don't know where you come up with it, but this was not working.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main ()
{
int i;
char full_string[100];
char reduce_string[100];
char file_name_for_read[128];
char file_name_for_save[128];
printf("Enter file name for read...\n");
scanf ("%s", file_name_for_read);
strcat(file_name_for_read,".txt");
FILE *fileA;
fileA=fopen(file_name_for_read,"r");
printf("Enter file name for save...\n");
scanf ("%s", file_name_for_save);
strcat(file_name_for_save,".txt");
FILE *fileB;
fileB=fopen(file_name_for_save,"w");
while(fgets(full_string, 50, fileA) !=NULL)
{
int cnt = 0;
for(i = 2; i < strlen(full_string)-3; i+=3)
{
reduce_string[cnt++] = full_string[i];
}
fprintf(fileB, "%s", reduce_string);
}
fclose(fileA);
fclose(fileB);
}

ANSI C strcmp() function never returning 0, where am I going wrong?

C isn't the language I know so I'm out of my comfort zone (learning C) and I have ran into an issue that I can't currently figure out.
I am trying to read from a text file one word at a time and compare it to a word that I have passed into the function as a pointer.
I am currently reading it from the file one character at a time and storing those characters in a new char array until it hits a space, then comparing that char array to the original word stored in the pointer (stored where it's pointing to, anyway).
When I do a printf to check if both arrays are the same they are, they both equal "Hello". At first I thought maybe it's because my char array doesn't have an end terminator but I tried adding one but still nothing is seeming to work.
My code is below and I would appreciate any help. Again C isn't my strong area.
If I do "Hello" it will be > 0 by the way, so I think it's because the gets() stdin function is also including the enter key or something of that sort. I am not sure of a better way to grab the string though.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int partA(char*);
main()
{
// Array to store my string
char myWord[81];
// myword = pointer to my char array to store. 80 = the size (maximum). stdin = standard input from my keyboard.
fgets(myWord, 80, stdin);
partA(myWord);
}
int partA(char *word)
{
// points to file.
FILE *readFile;
fopen_s(&readFile, "readThisFile.txt", "r");
char character;
char newWord[50];
int i = 0;
while ((character = fgetc(readFile)) != EOF)
{
if (character == ' ')
{
newWord[i] = '\0';
int sameWord = strcmp(word, newWord);
printf("Word: %s", word);
printf("newWord: %s", newWord);
if (sameWord == 0)
printf(" These words are the same.");
if (sameWord > 0)
printf(" sameWord > 0.");
if (sameWord < 0)
printf(" sameWord < 0.");
printf("\n");
i = 0;
}
if (character != ' ')
{
newWord[i] = character;
i++;
}
printf("%c", character);
}
fclose(readFile);
return 1;
}

Resources