Split file with commas, storing values in an 2-d array - c

Currently working on how to split a .csv file with ",". Then creating a
2-D array to store the Alphabet and the number together. As it stands, the code below outputs: "a,,,,,,,,,,,,,,,,,,,". Also, what is the appropriate data type to declare the 2-D array since the values would be Char and int? Furthermore, I know this is a duplicate question because I've not found previous questions helpful. A simple explanation would be great and appreciated, explanation on how to split the file with this piece code would be perfect "%*[^,]" if possible. Thanks in advance.
Sample contents of the .csv file below.
A,1
B,2
C,3
.....
The program:
char single;
/* char array[26][2]; I was thinking the 2-d array would be declared like that. */
while ((single = fgetc(fpointer)) != EOF)
{
fscanf(fpointer,"%*[^,]");
printf("%c",single);
}
fclose(fpointer);
............................................................
edit code: With strtok() and fgetc()
............................................................
//char single;
char s[26] = ",";
char *token;
char str[100];
while (fgets(str,100,fpointer))
{
while((token = strtok(NULL, s)) != NULL)
{
printf(" %s\n", token);
}
}
fclose(fpointer);

typedef struct
{
char charVal;
int intVal;
}SplitValue;
SplitValue result[50];
int count = 0;
FILE *myFile = NULL;
fopen_s(&myFile, "mycsvfile.csv", "r");
char single[100];
if (myFile != NULL)
{
while (fgets(single, 100, myFile) != NULL)
{
// store the first char value
result[count].charVal = single[0];
// store the int value as string
char intval[25];
int i = 0;
for (i = 2; single[i] != '\n'; ++i)
{
intval[i - 2] = single[i];
}
intval[i-2] = 0;
// convert the string to int, either using atoi or sscanf
result[count].intVal = atoi(intval);
// get ready for the next item
count++;
}
fclose(myFile);
}
if (count)
{
for (int i = 0; i < count; ++i)
{
printf("Char value: %c and int value: %d\n", result[i].charVal, result[i].intVal);
}
}
Hope this helps!

Try the following solution, considering comments from DYZ and RoadRunner. Hope it helps somehow.
#include <stdio.h>
#include <stdlib.h>
typedef struct charIntPair {
char alpha;
int value;
} charIntPair_t;
#define MAX_ALPHABET_LENGTH 26
charIntPair_t myAlphabet[MAX_ALPHABET_LENGTH];
int alphabetLength = 0;
int main() {
FILE *fp = fopen("mycsvfile.csv","r");
if (!fp)
return 1; // File could not be opened.
char line[100];
for (alphabetLength=0; alphabetLength < MAX_ALPHABET_LENGTH && fgets(line,100,fp); alphabetLength++) {
int elementsRead = sscanf (line,"%c,%d",
&myAlphabet[alphabetLength].alpha,
&myAlphabet[alphabetLength].value);
if (elementsRead < 2) // not a valid char/int-combination?
break;
}
for (int i=0; i<alphabetLength; i++) {
printf("element %d is (%c,%d)\n", i, myAlphabet[i].alpha, myAlphabet[i].value);
}
return 0;
}
It expects that the character is the first element in a line and that it is immediately followed by a ,. The number may have spaces upfront. The following input yields the following output:
A,1
B,2
C, 3
D,15
E,17
=>
element 0 is (A,1)
element 1 is (B,2)
element 2 is (C,3)
element 3 is (D,15)
element 4 is (E,17)

Related

Return pointer to array of strings C

I am trying to return an array of strings that are taken from a file. The file looks like this (first line is number of words, and every new line is word). I get some weird output in main part when functions are over. I want to return pointer to array of strings. Note that some part of code that uses printing is for checking my program.
Here is the function that allocates memory:
char *generisiProstor(int n) {
return (char*)malloc(n*sizeof(char[20]));
}
This is function for taking words from rijeci.txt and should return pointer to array of strings that contains the words:
char* ucitajRijeci(int n) {
char i;
char *rijeci;
static const char filename[] = "rijeci.txt";
FILE *file;
file = fopen(filename, "r");
if (file != NULL)
{
char line[20];
int n;
fscanf(file, "%d", &n);
rijeci = generisiProstor(n);
if (rijeci == NULL) {
return NULL;
}
int i = -1;
fgets(line, 20, file); //skipping first line witch is integer and not needed
while (fgets(line, 20, file) != NULL)
{
printf("%s\n", line); //normal output
i++;
strcpy(rijeci + i, line);
printf("%s\n", rijeci + i); //normal expected output
}
for (i = 0; i < n; i++) {
printf("%s\n", rijeci + i); //wrong output
}
}
return rijeci;
}
Main
int main()
{
static const char filename[] = "rijeci.txt";
FILE *file;
file = fopen(filename, "r");
char *rijeci;
int i;
if (file != NULL)
{
char line[20];
int n;
fscanf(file, "%d", &n);
rijeci = ucitajRijeci(n);
printf("Here is the array: ");
for (i = 0; i < n; i++) {
printf("%s ", rijeci+i); //wrong output
}
}
return 0;
}
Here you have to use 2-dimensional array (char ** instead of char *). Since you are returning 2-d array you have to declare rijeci as char **rijeci;
Return types of both functions should be also char **.
Change rijeci + i to rijeci[i].
Proper code indentation.
Try this modified code. This will work :-
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* generisiProstor */
char **generisiProstor(int n)
{
char **c; // making 2-d array
c = (char **)malloc(n * sizeof(char *));
for (int i = 0; i < n; i++)
{
c[i] = (char *)malloc(20 * sizeof(char));
}
return c;
}
/* ucitajRijeci */
char **ucitajRijeci(int n)
{
char **rijeci; // change to char **
static const char filename[] = "rijeci.txt";
FILE *file;
file = fopen(filename, "r");
if (file != NULL)
{
char line[20];
int n;
fscanf(file, "%d", &n);
rijeci = generisiProstor(n);
if (rijeci == NULL)
{
return NULL;
}
int i = -1;
fgets(line, 20, file); //skipping first line witch is integer and not needed
while (fgets(line, 20, file) != NULL)
{
printf("%s\n", line); //normal output
i++;
strcpy(rijeci[i], line);
printf("%s\n", rijeci[i]); //changed to rijeci[i]
}
for (i = 0; i < n; i++)
{
printf("%s\n", rijeci[i]); //changed to rijeci[i]
}
}
return rijeci;
}
/* main() */
int main()
{
static const char filename[] = "rijeci.txt";
FILE *file;
file = fopen(filename, "r");
char **rijeci; // change to char **
int i;
if (file != NULL)
{
char line[20];
int n;
fscanf(file, "%d", &n);
rijeci = ucitajRijeci(n);
printf("Here is the array: ");
for (i = 0; i < n; i++)
{
printf("%s ", rijeci[i]); //changed to rijeci[i]
}
}
return 0;
}
The first problem you encounter is here:
char *generisiProstor(int n) {
return (char*)malloc(n*sizeof(char[20]));
}
You want an array of char pointers, but you return a char pointer, or an array of char.
This part should be:
char **generisiProstor(int n) {
return (char**)malloc(n*sizeof(char[20]));
}
The same problem comes with char *rijeci, you are declaring it as a string or a char pointer.
You should declare it like this char **rijeci (you might want it to be char *(rigeci[20]) in this context) so this will be an array of strings.
If I get your code right another problem might come from this part:
while (fgets(line, 20, file) != NULL)
{
printf("%s\n", line); //normal output
i++;
strcpy(rijeci + i, line);
printf("%s\n", rijeci + i); //normal expected output
}
Earlier in the code, you allocate memory for n words. Here you are reading the line, placing it into line. So when you read the first line i is 0, but you increment it before copying it, so your array has its first occurence unset and you are writing the last word on unallocated memory.
This part should be:
while (fgets(line, 20, file) != NULL)
{
printf("%s\n", line); //normal output
strcpy(rijeci + i, line);
i++
printf("%s\n", rijeci + i); //normal expected output
}
If you want to return a pointer to a char array of size 20 you have to declare the function as following:
char (*generisiProstor(int n))[20]
{
return malloc(n*sizeof(char[20]));
}
The variable which holds the pointer to the arrays is declared as:
char (*rijeci)[20];
rijeci[i] is of type char[20] and you can write your strings there.
Do you know the definitions of array and string?
I'll give them to you, as given in the 2011 C-standard:
An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type. […]
A string is a contiguous sequence of characters terminated by and including the first null character. […]
Thus, an array is a type derived from a complete object-type, but a string is not a type but a data-structure.
You are very cast-happy. Are you sure forcing the compiler to believe you without cause is a good habit to get into? Also prefer sizeof expr over sizeof (TYPE), as it's harder to get wrong initially or out-of-sync when refactoring later.
Consider reading "Do I cast the result of malloc?".
You're allocating the correct amount of memory, but you need to change how you use it. malloc() can only return a "flat" array of characters, so the return value from generisiProstor() is a simple pointer to the first character in the whole array.
The reason it's working initially is that each string overwrites the tail end of the previous string, so when you do the print outs during the read in loop, they show correctly. But even so, the payload of your rijeci array is completely corrupt by the time you've finished reading.
One possible solution is to use a struct to hold your words:
struct Rijec
{
char rijec[20];
};
and then change generisiProstor(int n) to be this:
struct Rijeci *generisiProstor(int n)
{
return malloc(n * sizeof(struct Rijec));
}
Note that the cast is not needed in C, and indeed should be avoided.
Then, you'll need to change the top of ucitajRijeci() to look like this:
struct Rijec *ucitajRijeci(int n)
{
struct Rijec *rijeci;
...
and in all cases where you're using rijeci + i change that to rijeci[i].rijec.
The net result of this is that when you use i to index a word in the rijeci array, the offset will now be correct.

Storing strings from a text file into a two dimensional array

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

Storing the buffer of fgets in Array

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);
}

Why is this zero printing inbetween my code?

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#define MAX_KEYS 26
#define MAX_UID 4
struct Key {
int keynum;
int id;
char cryptkeys[65];
};
int main(int argc, char ** argv) {
int MAX_LINE = 69;
struct Key *table = malloc(MAX_UID * sizeof(struct Key));
FILE *fileopen = fopen(filename, "r");
char *a[8];
int size = 0;
char *e;
char *string = NULL;
//reading the file
if(fileopen) {
while((e = fgets( line, MAX_LINE, fileopen )) != NULL) {
printf(e);
a[size] = strdup(e);
size++;
}
}
else {
printf("File does not exist\n");
exit(0);
}
for(int i = 0; i < size; i++ ) {
//printf("%s", a[i]); //no zero showing up
}
//parsing the id and the keys
char id[3];
char key[65];
int ids;
int idnum;
for(int i = 0; i < size-1; i++) {
struct Key *k = (struct Key*)malloc(sizeof(struct Key));
string = a[i];
//set the ID
for(int ix = 0; ix < 3; ix++) {
id[ix] = string[ix];
}
//printf("%s", id); No zero inbetween ID
//set the Keys
for(int j = 4; j < 68; j++) {
key[j-4] = string[j];
}
ids = strtol(string, &id2, 10);
//printf("Id is %d", ids); //zero shows up here
//printf(" ");
k->id = ids;
strcpy(k->cryptkeys, key);
k->keynum++;
table[i] = *k;
idnum++;
}
for(int i = 0; i < 5; i++) {
printf("%d", table[i].id);
printf(" ");
printf("%s", table[i].cryptkeys);
printf("\n");
}
return 0;
}
Hey guys, I'm trying to work on struct manipulation inside array of pointers to my structs. I can add the values just fine, but I keep getting this 0 appearing between my lines.My file is only three lines long with an integer and a string afterwards. Everything seems to parse correctly but a zero keeps showing up in my text.
My file looks like this in case you were wondering
421 0123456789abcdef0123456789abcde00123456789abcdef0123456789abcde0
422 0000000000000000000000000000000000000000000000000000000000000000
423 1111111111111111111111111111111111111111111111111111111111111111
and when I try to print the output after reading in my table it looks like this.
421 0123456789abcdef0123456789abcde00123456789abcdef0123456789abcde0
0
422 0000000000000000000000000000000000000000000000000000000000000000
0
423 1111111111111111111111111111111111111111111111111111111111111111
I dont think it is coming from the back of the strings because each key is the appropriate length. Any suggestions on what it might be coming from? Any help would be greatly appreciated.
The function fgets will read line in string line until MAX_LINE characters are read or it hits new line.
Hence you can first allocate line string with sufficient memory to read line. In this case it is MAX_LINE .
char line[MAX_LINE];
char *a[8];
while((e = fgets( line, MAX_LINE, fileopen )) != NULL)
{
printf(line);
a[size] = strdup(line);
size++;
}
The main problem is that you use strcpy(k->cryptkeys, key); where key is not null-terminated. You only write to the first 64 elements and leave the last one uninitialized.
But there are some general issues as well, e.g. you're leaking memory because you call malloc in the loop without freeing (you could write the program just fine without using malloc at all) and you're unneccessarily reading the whole file into memory.

C parser for data separated with comma

What is the most effective way to write a parser in C for data with the following format:
atr#1,atr#2,...,atr#n
btr#1,btr#2,...,btr#n
...
Each record is in new line and attributes are separated with comma.
What function should be used? Do you have any examples?
Here's some example code that will read the file sparated by newlines line by line, then split the arguments and print them out (you can easily adapt it to, for example, parse it to an array of array of char *s):
#include <stdio.h>
#include <string.h>
int main()
{
FILE *f = fopen("file.txt", "r");
char ptr[1024];
char *token;
while (fgets(ptr, 1024, f) != NULL)
{
token = strtok(ptr, ",");
while(token)
{
printf("Token: %s\n", token);
token = strtok(NULL, ",");
}
}
fclose(f);
return 0;
}
This will work:
/* You need the following includes and defines */
#include <stdio.h>
#include <iostream.h>
#include <string.h>
#define NULL_CHAR 0x0
int parse(char* data) {
const int LINE_SIZE=255; /* Should be long enough for your unparsed data */
const int MAX_FIELDS=99; /* Maximum number of fields */
char output[MAX_FIELDS][LINE_SIZE];
int i;
int output_field_count;
int output_char_idx;
for (i = 0; i < MAX_FIELDS; i++) {
strcpy(output[i], "");
}
output_field_count = 0;
output_char_idx = 0;
for (i = 0; i < LINE_SIZE; i++) {
if ((data[i] != ',') &&
(output_field_count < MAX_FIELDS) &&
((output_char_idx+1) < LINE_SIZE)) {
output[output_field_count][output_char_idx] = data[i];
output[output_field_count][output_char_idx+1] = NULL_CHAR;
output_char_idx++;
}
else if (data[i] == ',') {
output_field_count++;
output_char_idx = 0;
}
}
output_field_count++;
output_char_idx = 0;
printf("OUTPUT FIELD COUNT IS: %d\n", output_field_count);
for (i = 0; i < output_field_count; i++) {
printf("FIELD %i IS: %s\n", i, output[i]);
}
return 0;
}
This can be called as follows:
char data[500]; /* Should be long enough for your unparsed data */
strcpy(data, "atr#1,atr#2,...,atr#n");
parse(data);
strcpy(data, "btr#1,btr#2,...,btr#n");
parse(data);
Pick the right tool for the job. It's about one line in Perl, Python, or best yet awk. If you have a compelling reason to use C, please explain in your post - otherwise I think the most judicious answer anyone can give you is to advise you to pick the right tool for the job instead of asking how to do something onerous in a language that's bad at it.
From the command line:
tr ',' '\n' < file.txt
Will turn the commas into new lines.

Resources