Array of of Struct containing array of char as members - C [closed] - c

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have a struct like this:
struct vertices{
char x[20];
char y[20];
char z[20];
};
and then in main I have an array of the struct vertices like this:
struct vertices vert[64];
plus an array of char in my main function like this:
char exampleArray[200]="v 23.232000 32.33000 2.03900\nv 9.20900 3.29000 1.0002\n";
so what I want to do is to parse this big array containing a hundred or so vertices, and store each value in the corresponding x,y,z char arrays of the struct vertices, which later I'm gonna simply convert by calling on
float x=atof(vert[1].x) and draw each one.
But the problem is that I can't store , copy, concat characters from the raw array to the x,y,z arrays by any ways, i tried to do it by vert[0].x=exampleArray[0], vert[0].x=exampleArray+i etc inside different conditions like
if(SpaceCount==1)
{
vert[0].x[0]=exampleArray[i];
i++;
}
but all this doesn't work.
I tried so many variations, couldn't list them all.
But the thing I want is to parse the exampleArray which has my vertices in raw format, every 3D vertix has spaces in between them, every vertix starts with a char V followed by a space, the first point is the X then followed by a space and then the Y point and after the Z point there is newline \n character and then again a V for a new vertix.

You could use strtok() with delimiter " \n" to get each piece and then strcpy() to place each token in your struct.
struct vertices {
char x[20];
char y[20];
char z[20];
};
int main(void)
{
char exampleArray[200] = "v 23.232000 32.33000 2.03900\nv 9.20900 3.29000 1.0002";
char *toStrtokVertex, *token;
char delim[5] = " \n";
struct vertices V[10];
int i = 0;
toStrtokVertex = exampleArray;
while ((token = strtok(toStrtokVertex, delim)) != NULL) {
// ignore the `v`
// get x
if ((token = strtok(NULL, delim)) != NULL) {
strcpy(V[i].x, token);
}
else {
printf("INPUT ERROR\n");
exit(1);
}
// get y
if ((token = strtok(NULL, delim)) != NULL) {
strcpy(V[i].y, token);
}
else {
printf("INPUT ERROR\n");
exit(1);
}
// get z
if ((token = strtok(NULL, delim)) != NULL) {
strcpy(V[i].z, token);
}
else {
printf("INPUT ERROR\n");
exit(1);
}
// switch this to NULL to keep parsing the same string
toStrtokVertex = NULL;
i++;
}
for (int j = 0; j < i; j++) {
printf("V[%d] (%s, %s, %s)\n", j, V[j].x, V[j].y, V[j].z);
}
}
Note that I modified your input value to match your description. You had
"v 23.232000 32.33000 2.03900\n 9.20900 3.29000 1.0002"
which did not have a v after the \n to start the next vertex, so I added a v
"v 23.232000 32.33000 2.03900\nv 9.20900 3.29000 1.0002"

Character arrays are not copied by simply pointing at them. The function "strcpy(vert[0].x, &exampleArray[2])" is needed, but even then there is no '\0' immediately after that first number to indicate where to stop reading. "memcpy" does not need a NULL ('\0') but needs a length based on spaces.
Further, the "atof" operation to plan to use requires a NULL terminator as well.
I am concerned with your "space planning". You have 64 copies of structures that will each require 60 characters (3840 total), but your exampleArray only has 200. And the input string exampleArray has strings for numbers that must be no longer than 19 digits/decimals because you need the NULL terminator in each of x/y/z to exist.
This is the pure technical evaluation of code issues, but your original post does not show more of the application design. Help us understand your application design and more advice can be given.

Related

C How to properly fscanf with numbers and strings?

I'm writing a game in SDL2 for a school project, in C, I have a config that lists key-values pairs as such:
groundTiles: images/Overworld/groundTiles.png
and
cellHeight: 32
How should I go about parsing this data? Because my attempts result in the integers being read correctly but strings are either missing chars or are completely corrupt. I'm somewhat of a beginner to C, at least in terms of file i/o
I need another set of eyes on this code because I've spent too many hours on this already.
Could it have something to do with this struct in my header and how I'm using it to store temporary data?
typedef struct TileMapData_S
{
Uint32 col, row, cellWidth, cellHeight, numCells;
char *mapName;
char *emptyTileName;
Bool flag;
SDL_Color *colors;
Tile* tileTypes;
char *colorMap;
}TileMapData;
I've tried making it an unnamed struct in the function, then the source. No luck. I tried just not using a struct and fscanf'ing each piece of data into a separate variable. Same thing, no luck. If I did fscanf(file, "%s %s", buf, temp) with temp being the value of the key I'm parsing, then I get the first encounter of the string I'm looking for, then it copies itself to the other two char* that are holding the names of my sprites/files.
EDIT: This is my attempt based on comments, which does not work, any insight would be appreciated
while (!data->flag)
{
while (tempString != EOF)
{
tempString = strtok(buf, " \n");
if (strcmp(tempString, "width:") == 0)
{
tempString = strtok(buf, "\n\0 ");
map->numColumns = atoi(tempString);
continue;
}
.
.
.
if (strcmp(tempString, "groundTiles:") == 0)
{
data->mapName = strtok(buf, "\n\0 ");
data->mapName = tempString;
if (data->mapName != NULL)
{
data->flag = true;
}
else
{
data->flag = false;
}
continue;
}
.
.
.
tempString = fgets(buf, sizeof(buf), file);
slog(buf);
}
rewind(file);
}
I was expecting to get the string I wanted, without the whitespace/null-terminating char, but ended up with an infinite loop
END EDIT
I expect that when I parse groundTiles: images/Overworld/groundTiles.png
using fscanf(file, "%s", buf), doing strcmp on that and a known string (groundTiles:), then a second fscanf should provide the string images/Overworld/groundTiles.png

How would I read a line, parse the information and then attribute it to a struct in C?

I am currently trying to understand how to go through a .txt file in C and I think I have mostly everything worked out but what I need to do is kind of confusing. I need to create an array of Pointers to point to structs.
Each line in my .txt file should have information corresponding to a single struct. Each line should start with a name followed by some float values.
My question is, when I read the lines and parse them using strtok first, how would I get that information in a struct?
second how would I then make the sample pointer at index i point to the struct?
I tried doing the name seperate from the numbers since the numbers need their own special atof conversion since initially it will be a string. However I think this is probably incorrect since I want to read multiple lines, the code I have before the while loop for obtaining the name will only run once so any following lines will not have the name seperated. I can technically delimit my text file as I choose, so maybe I can just seperate the name with a semicolon and the rest spaces?
If this question seems confusing its probably because I am over thinking
Should I be declaring a struct such as : Sample tmp;
I've been reading examples but I can't figure out how to put the information together. Let me know if I declared my array of pointers incorrectly... Which I think I did. I think my the line that says:
sample arr[SIZE] = {NULL}; might be incorrect but I am not sure. if you can help me work out the logic behind all this I would appreciate it. Thanks.
typedef struct sample{
char* name;
int list_len;
float* value_list;
}sample;
void read_and_parse(){
const int SIZE = 1024;
sample* sample = (sample*)malloc(sizeof(sample); //pointer allocation?
FILE* fin;
fin = fopen("record.txt", "r");
if (fin == NULL) {
printf("record.txt could not be opened \n");
exit(1);
}
else {
int i= 0;
sample arr[SIZE] = {NULL}; //here I try to make the array of pointers
char linebuf[SIZE];
token = strtok(linebuf, " "); //grab the first item
while (fgets(linebuf, SIZE, fin) && i<SIZE) {
arr[i] = malloc(sizeof(sample));
arr[i.name] = token;
token = strtok(NULL, " ");
// now parse the linebuf and fill arr[i] with it
i++;
}
Edited: 11/02/2017
any print statements you see are just silly markers I placed for testing and recognizing what is running when I finally get this code compiled
Here is a much better edited version of the code. I think it should work now.
typedef struct sample{
char* name;
int list_len;
float* value_list;
}sample;
void read_and_parse(FILE **fin, sample* arr[]){
const int SIZE = 1024;
if (*fin == NULL) {
printf("record.txt could not be opened \n");
exit(1);
}
else {
printf("successfully opened file\n");
char linebuf[SIZE];
while ( fgets(linebuf, SIZE, fin) ) {
arr[i] = malloc(sizeof(sample));
int floats_per_line = 0;
while(linebuf[i]){
if(linebuf[i] == ' ');
++floats_per_line;
}
arr[i]->list_len = values_per_line;
arr[i]->value_list = (float*)malloc(sizeof(float)*floats_per_line);
arr[i]->name = strdup(strtok(linebuf, ' '));
char* tok;
int j = 0
while(tok = strtok(NULL, ' ')){
arr[i]->value_list[j] = atof(tok);
++j
}
i++;
}
}
fclose(fin);
}
How would I read a line, parse the information and then attribute it to a struct ?
Read with fgets() which converts a line of file input into a string. OP does that well. Then parse the string.
when I read the lines and parse them using strtok first, how (to) get that information in a struct?
Should I be declaring a struct such as : sample tmp;
Pass the string to a helper function to parse it into a sample that can hold any input. So the pointer members of tmp need to point to maximal space.
char name[SIZE];
char f[SIZE/2];
sample tmp = { name, 0, f };
while (i<SIZE && fgets(linebuf, SIZE, fin)) {
if (sample_parse(&tmp, linebuf) == NULL) {
break; // Parsing failed for some reason, perhaps an error message?
}
// Now populate arr[i] with right-sized memory allocations
arr[i].name = strdup(tmp.name); // ToDo: add NULL check
arr[i].list_len = tmp.list_len;
size_t f_size = sizeof *(tmp.value_list) * tmp.list_len;
arr[i].value_list = malloc(f_size); // ToDo: add NULL check
memcpy(arr[i].value_list, tmp.value_list, f_size);
i++;
}
so maybe I can just separate the name with a semicolon and the rest spaces?
Yes. Also allow other white-spaces too.
if I declared my array of pointers incorrectly.
Code does not have an array of pointers anywhere.
Recommend using size_t for array size type.
typedef struct sample {
char* name;
// int list_len;
size_t list_len;
float* value_list;
} sample;
Some untested code for parsing. Parse the line with strtok(). Further parse the number tokens with strtof().
#define sample_NAME_DELIMITER ":"
#define sample_NUMBER_DELIMITER " \n\t\r"
// parse for a name and then 0 or more numbers
static sample *sample_parse(sample *dest, char *linebuf) {
char *s = strtok(linebuf, sample_NAME_DELIMITER);
if (s == NULL) {
return NULL; // no name - TBD on if this is allowed
}
strcpy(dest->name, s);
size_t i = 0;
while ((s = strtok(NULL, sample_NUMBER_DELIMITER)) != NULL) {
char *endptr;
dest->value_list[i] = strtof(s, &endptr);
if (s == endptr || *endptr) {
// conversion failed or extra junk
break;
}
i++;
}
dest->list_len = i;
return dest;
}

Put each word of a string into array in C [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm trying to split up a string (typed in by the user at run time) into words (separated by spaces), and put each word into a different slot into an array. So, for example, if I took the string "hello world", array[0] would contain "hello" and array[1] would contain "world". And the last slot (in this case array[2]) would contain NULL. Here's what I have so far, which doesn't seem to be working properly. Any help would be appreciated. (By the way, this is part of a program which will call execvp(argv[0],argv); )
char input[100];
char* argv[20];
char* token;
scanf("%s", input);
//get the first token
token = strtok(input, " ");
int i=0;
//walk through other tokens
while( token != NULL ) {
argv[i] = token;
i++;
token = strtok(NULL, " ");
}
argv[i] = NULL; //argv ends with NULL
You need to allocate memory for each argv[i] and copy the current token to argv[i]:
token = strtok(input, " ");
int i=0;
//walk through other tokens
while( token != NULL ) {
argv[i] = malloc(strlen(token) + 1);
strncpy(argv[i], token, strlen(token));
//argv[i] = token;
i++;
token = strtok(NULL, " ");
}
argv[i] = NULL; //argv ends with NULL
I have created an example of what I think you want. I have used one malloc(3) for the whole
line of strings and another for the array of pointers you will get from the function.
Also, the second parameter of strtok(3) is passed to give more flexibility (the shell normally uses the contents of IFS environment variable to separate arguments so you can use the same algorithm as the shell does) I think you should use " \n\t" at least. It has a main() test function, so it's complete for your purpose.
#include <assert.h> /* man assert(3) */
#include <stdlib.h> /* malloc lives here */
#include <string.h> /* strtok, strdup lives here */
#include <stdio.h> /* printf lives here */
char **split(const char *str, const char *delim)
{
char *aux;
char *p;
char **res;
char *argv[200]; /* place for 200 words. */
int n = 0, i;
assert(aux = strdup(str));
for (p = strtok(aux, delim); p; p = strtok(NULL, delim))
argv[n++] = p;
argv[n++] = NULL;
/* i'll put de strdup()ed string one place past the NULL,
* so you can free(3), once finished */
argv[n++] = aux;
/* now, we need to copy the array, so we can use it outside
* this function. */
assert(res = calloc(n, sizeof (char *)));
for (i = 0; i < n; i++)
res[i] = argv[i];
return res;
} /* split */
int main()
{
char **argv =
split("Put each word of a string into array in C", " ");
int i;
for (i = 0; argv[i]; i++)
printf("[%s]", argv[i]);
puts(""); /* to end with a newline */
free(argv[i+1]);
free(argv);
} /* main */
The sample code just outputs:
$ pru
[Put][each][word][of][a][string][into][array][in][C]
I think I just figured out my problem: I need to use gets() instead of scanf(), because scanf() only gets the first word, up until a space, while I want to be able to get a string containing multiple words separated by spaces.

Tokenize the string in c

i need to tokenize the string in c. suppose if i have a string like this
"product=c,author=dennis,category=programming".
I want to extract only the values among these key values pairs. Like
[c,dennis,programming].
I have used strtok function which tokenizes with "=" and I get values
[product,c,author,dennis,category,programming].
Is there any built in function that can generate only the values like mentioned above.
Just a simple scanf
#include<stdio.h>
int main()
{
char token[20] = { 0 };
char c, name[20];
int i=0, offset;
while (scanf("%[a-z]%*[^a-z]", token) == 1) {
i++;
if(i%2==0)
printf("[%s]\n",token );
}
return 0;
}
./a.out
product=c,author=dennis,category=programming,
[c]
[dennis]
[programming]
Ctrl+D
Note. I have added , at the end of the string
You could simply skip every second token like that:
#include <stdio.h>
#include <string.h>
int main(void) {
char str[] = "product=c,author=dennis,category=programming";
char* p = strtok(str, ",=");
while (p != NULL) {
p = strtok(NULL, ",=");
if (p != NULL) {
printf("%s\n", p);
strtok(NULL, ",="); // skip this
}
}
return 0;
}
I can think of a couple of ways:
First tokenize on ,, then split each part on the =.
Find the first =, then the , after it, and get the word in between. Repeat.
If there are always three values, you can use sscanf to read the values.
You can use a regex library to parse the string.
You can first tokenize on ,, splitting the contents into 3 different strings, then tokenize on '=' for each of those strings:
char *kvpair[N] = {NULL}; // where N is large enough for the expected
// number of key-value pairs
char *tok = strtok(input, ",");
size_t kvcount = 0;
while (tok != NULL && kvcount < N)
{
kvpair[kvcount++] = tok;
tok = strtok(NULL, ",");
}
...
for (i = 0; i < kvcount; i++)
{
char delim = '[';
char *key = strtok(kvpair[i], "=");
char *val = strtok(NULL, "=");
printf("%c%s", delim, val);
delim = ',';
}
putchar(']');
This is just a rough sketch; it assumes that the maximum number of key-value pairs is known ahead of time, it doesn't attempt to handle empty keys or values, or really do any sort of error handling at all. But it should point you in the right direction.
Remember that strok modifies its input; if your original data is a string literal or if you need to preserve the original data, you'll need to make a copy and work on that copy.
Note that, because of how strok works, you can't "nest" calls; that is, you can't tokenize the first key-value pair, then split it into key and value tokens, then get the next key-value pair. You'll have to tokenize all the key-value pairs first, then process each one in turn.

Working with tokenizing in c

I am trying to tokenize a line and put it into a two dimensional array so far I have come up with this but I feel I am far off:
/**
* Function to tokenize an input line into seperate tokens
*
* The first arg is the line to be tokenized and the second arg points to
* a 2-dimentional string array. The number of rows of this array should be
* at least MAX_TOKENS_PER_LINE size, and the number of columns (i.e., length
* of each string should be at least MAX_TOKEN_SIZE)
*
* Returns 0 on success and negative number on failure
*/
int __tokenize(char *line, char tokens[][MAX_TOKEN_SIZE], int *num_tokens){
char *tokenPtr;
tokenPtr = strtok(line, " \t");
for(int j =0; j<MAX_TOKEN_SIZE; j++){
while(tokenPtr != NULL){
if(!(tokens[][j] = tokenPtr)){return -1;}
num_tokens++;
tokenPtr = strtok(NULL, " \t");
}
}
return 0;
}
int __tokenize(char *line, char tokens[][MAX_TOKEN_SIZE], int *num_tokens)
{
char *tokenPtr;
tokenPtr = strtok(line, " \t");
for (int i = 0; tokenPtr; i++)
{
tokens[i] = tokenPtr;
tokenPtr = strtok(NULL, " \t");
}
}
Hope this should work.
You should implement a finite state machine, I've just finish my shell command Lexer/Parser (LL)
Look : How to write a (shell) lexer by hand
tokenPtr is not initialized - it may or may not be NULL the first time through the loop.
strtok takes 2 arguments. If you want to split on multiple chars, include them all in the 2nd string.
After the strtok call, token pointer points to the string you want. Now what? You need somewhere to store it. Perhaps an array of char*? Or an 2d array of characters, as in your edited prototype.
tokens[i] is storage for MAX_TOKEN_SIZE characters. strtok() returns a pointer to a string (a sequence of 1 or more characters ). You need to copy one into the other.
What is the inner loop accomplishing?
Note that char tokens[][MAX] is usually referred to as a 2-D array of characters. (or a 1-D array of fixed-length strings). A 2-D array of strings would be char* tokens[][MAX]

Resources