Reputation: 53
I'm trying to count the number of columns from within a txt.file Example file (txt_file.txt):
aaron 1 2 3
bethi 1 2 3
dylan 1 2 3
kevin 1 2 3
This is my code snippet: (main.c)
int main(int argc, char *argv[])
{
//File based variables
char line[1024] = {0x0};
char name[100] = {0x0};
int i, j;
//Array based variables
int students = 0,
assignments = 0,
count = 0;
//File pointer, refer to file as fp now.
FILE *fp;
printf("the input file name is %s\n", argv[1]);
if ( fp == NULL )
{
puts ( "Cannot open source file");
}
// open file in read mode & get size
fp = fopen(argv[1], "r");
**get_data_size(fp,&students,&assignments);** //Function returning junk
//MY array for grades
//-------------------------------------------
int **grades = (int **)malloc(assignments * sizeof(int *));
for (i = 0; i < assignments; i++)
{
grades[i] = (int *)malloc(students * sizeof(int));
if (grades[i] == NULL)
{
fprintf(stderr, "Not enough memory to allocate\n");
exit(1);
}
}
Code snippet for get_data_size function: (Use: find and determine size of file. Rows vs Columns)
void get_data_size(FILE *fp, int *students, int *assignments)
{
//File based variables
char line[1024] = {0x0};
char name[100] = {0x0};
while(fgets(line, 1023, fp)) //rows
{
students++;
}
fseek(fp, 0, SEEK_SET);
char delims[] = ",";
char *result = strtok( line, delims );
while( result != NULL ) //columns
{
assignments ++;
printf( "result is \"%s\"\n", result );
result = strtok( NULL, delims );
}
//These are what return strange junk.
printf("The number of counts, or columns in the array is: %d\n",&assignments);
printf("The number of lines, or rows in the array is: %d\n",&students);
}
Upvotes: 0
Views: 3860
Reputation: 17468
Try strtok()
and strtok_r()
, it can strip the "Abc Efg Ghi"
to "Abc", "Efg", "Ghi"
, and you can count the total column and store "Abc", "Efg", "Ghi"
in a 2-D array.
char *strtok(char *str, const char *delim);
char *strtok_r(char *str, const char *delim, char **saveptr);
The strtok()
function returns a pointer to the next "token" in str1, where str2 contains the delimiters that determine the token. strtok()
returns NULL
if no token is found. In order to convert a string to tokens, the first call to strtok()
should have str1 point to the string to be tokenized. All calls after this should have str1 be NULL
.
Also, you can read the docs
For example:
char str[] = "Abc Efg Ghi";
char delims[] = " ";
char *result = NULL;
int count = 0;
result = strtok( str, delims );
while( result != NULL ) {
count ++;
printf( "result is \"%s\"\n", result );
result = strtok( NULL, delims );
}
printf("The total column is %d\n", count);
The above code will display the following output:
result is "Abc "
result is "Efg"
result is "Ghi"
The total column is 4
The following code read text from a file named test.csv, and store the data into 2-D array.
test.csv
alice, 22, 1992/03/05
bob, 33, 1981/11/21
cart, 40, 1974/07/13
readfile.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *trim(char *str)
{
char *p = str;
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
p ++;
str = p;
p = str + strlen(str) - 1;
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
-- p;
*(p + 1) = '\0';
return str;
}
int main()
{
int i, j;
char ** data = (char **)malloc(100 * sizeof(char *));
for (i = 0; i < 100; i ++)
{
data[i] = (char *)malloc(20 * sizeof(char));
}
char *** mydata = (char ***)malloc(3 * sizeof(char **));
for (i = 0; i < 3; i ++)
{
mydata[i] = (char **)malloc(3 * sizeof(char *));
for (j = 0; j < 3; j ++)
{
mydata[i][j] = (char *)malloc(20 * sizeof(char));
}
}
FILE *fp = fopen("test.csv", "r");
if(fp == NULL) {
return -1;
}
char line[1024];
int row = 0;
while(fgets(line, sizeof(line), fp))
{
//printf("%s", line);
char *save_ptr;
char *name = strtok_r(line, ",", &save_ptr);
if (name == NULL) {
return -1;
}
//printf("%s\n", save_ptr);
char *age = strtok_r(NULL, ",", &save_ptr);
//printf("%s\n", save_ptr);
char *birthday = strtok_r(NULL, ",", &save_ptr);
//printf("%s\n", save_ptr);
strcpy(mydata[row][0], trim(name));
strcpy(mydata[row][1], trim(age));
strcpy(mydata[row][2], trim(birthday));
//printf("%s\t%s\t%s\n", trim(name), trim(age), trim(birthday));
row ++;
}
for (row = 0; row < 3; row ++)
{
printf("%s\t%s\t%s\n", mydata[row][0], mydata[row][1], mydata[row][2]);
}
return 0;
}
The function split the ,
, and you can also split the " "
. You can change the code as your need.
Hope these two function can help you to store your data and get the column number.
Upvotes: 1
Reputation: 84561
A very simple way to count the columns of data in a string is to walk a pointer down the string and check each character. If a non-whitespace character is encountered, increase you count by 1 and then scan to find the next whitespace. Then simply scan forward while the characters continue to be whitespace until you find the next non-whitespace character and (repeat). A quick function that fits that bill could be something like:
/** count columns of data in a character string.
*/
int countcol (const char *s)
{
if (!s || !*s) return 0; /* validate input */
char *p = s; /* pointer to buf */
int col = 0; /* initialize col */
while (*p) { /* for each char in buf */
/* if p points to non-whitespace, col + 1 */
if (*p != ' ' && *p != '\t') col++, p++;
/* skip non-whitespace to find whitespace */
while (*p && *p != ' ' && *p != '\t') p++;
/* skip multiple whitespace together */
while (*p && (*p == ' ' || *p == '\t')) p++;
}
return col;
}
A small sample program that reads information on stdin
and counts the columns in each line could be:
#include <stdio.h>
enum { MAXC = 64 };
void rmcrlf (char *str);
int countcol (const char *s);
int main (void) {
char buf[MAXC] = "";
int col = 0;
while (fgets (buf, MAXC, stdin)) { /* read from stdin */
rmcrlf (buf); /* remove trailing '\n' read by fgets */
if (!*buf) continue; /* skip empty line */
col = countcol (buf);
printf ("'%s' (%d-col)\n", buf, col);
}
return 0;
}
/** stip trailing newlines and carraige returns by overwriting with
* null-terminating char. str is modified in place.
*/
void rmcrlf (char *str)
{
if (!str || !*str) return;
char *p = str;
for (; *p; p++)
if (*p == '\n' || *p == '\r') { *p = 0; break; }
}
/** count columns of data in a character string.
*/
int countcol (const char *s)
{
if (!s || !*s) return 0; /* validate input */
char *p = s; /* pointer to buf */
int col = 0; /* initialize col */
while (*p) { /* for each char in buf */
/* if p points to non-whitespace, col + 1 */
if (*p != ' ' && *p != '\t') col++, p++;
/* skip non-whitespace to find whitespace */
while (*p && *p != ' ' && *p != '\t') p++;
/* skip multiple whitespace together */
while (*p && (*p == ' ' || *p == '\t')) p++;
}
return col;
}
(note: adjust the constant MAXC
to meet your input length; also note the rmcrlf
function simply removes an carriage-returns or line-feeds ('\n'
) from the end of the string read by fgets
by overwriting either character with a 0
(the nul-terminating character))
Input File
$ cat dat/text_file.txt
aaron 1 2 3
bethi 1 2 3
dylan 1 2 3
kevin 1 2 3
Use/Output
$ ./bin/file_count_col <dat/text_file.txt
'aaron 1 2 3' (4-col)
'bethi 1 2 3' (4-col)
'dylan 1 2 3' (4-col)
'kevin 1 2 3' (4-col)
Let me know if you have any questions.
Upvotes: 2