Store splitted string in array - c

I using strtok() to split a string and store in an array like following below
char *table[5];
char buffer[50] = {"1-Study"}; // The value is example, get new value by user
char *number;
char *name;
uint8_t tableNumber;
number = strtok(buffer, "-"); //equals "1"
name = strtok(NULL, "-"); //equals "Study"
tableNumber = atoi(number); //convert char to int
table[tableNumber] = name;
for (c = 0; c < 5; c++)
{
printf("table %d = %s\n", c, table[c]);
}
after get input for 5 times the result should be:
table 0 = Study
table 1 = Sleep
table 2 = Party
table 3 = Hello
table 4 = Exit
But the resualt is:
table 0 = Exit
table 1 = Exit
table 2 = Exit
table 3 = Exit
table 4 = Exit
whats the problem?
please help me?
Thanks
complete code:
char gMessageBuffer[40];
char *gSceneTable[13];
boolean emberAfPreMessageReceivedCallback(EmberAfIncomingMessage* incomingMessage)
{
if (incomingMessage->apsFrame->profileId == HA_PROFILE_ID)
{
if (incomingMessage->apsFrame->clusterId == ZCL_SCENES_CLUSTER_ID)
{
MEMCOPY(gMessageBuffer, incomingMessage->message, incomingMessage->msgLen); // Get incoming message
gMessageBuffer[incomingMessage->msgLen] = '\0';
emberEventControlSetDelayMS(getScenePayloadEventControl, SCENE_ACTION_TRESH);
return true;
}
}
return false;
}
void getScenePayloadEventFunction(void)
{
char *sceneNumber;
char *sceneName;
char *sceneID;
char *sceneAction;
uint8_t sceneTableNumber;
emberAfCorePrintln("///Incoming Message: %s///", gMessageBuffer);
sceneNumber = strtok(gMessageBuffer, ".");
sceneName = strtok(NULL, ".");
sceneID = strtok(NULL, ".");
sceneAction = strtok(NULL, ".");
emberAfCorePrintln("///SCENE NUMBER: %s///", sceneNumber);
emberAfCorePrintln("///SCENE NAME: %s///", sceneName);
emberAfCorePrintln("///SCENE ID: %s///", sceneID);
emberAfCorePrintln("///SCENE ACTION: %s///", sceneAction);
if (strcmp(sceneAction, "Update") == 0)
{
sceneTableNumber = atoi(sceneNumber);
gSceneTable[sceneTableNumber] = strdup(sceneName);
}
emberEventControlSetInactive(getScenePayloadEventControl);
}
this is for microcontroller in simplicity studio IDE.
I get payload in emberAfPreMessageReceivedCallback correctly
and I split it into 4 parts and print correctly too.
But after copy the sceneName to gSceneTable array I see the last sceneName in all the elements of gSceneTable with gSceneTable[sceneTableNumber] = sceneName and I see "p]" with gSceneTable[sceneTableNumber] = strdup(sceneName);

It is highly unlikely that your program produce the posted output. The code fragment only handles a single string and char *table[5]; is uninitialized, so printing the strings from table[0], table[2], table[3] and table[4] has undefined behavior. You specified that the strings are read from a file, posting a complete program is required for a precise and correct analysis. Not initializing the array is a problem in case the file does not have all entries covered, it would be impossible to tell which were set and which weren't.
Assuming your program reads the strings from a file or standard input, parsing them with strtok returns pointers to the source string, which is the array into which you read the lines from the file. Hence all entries in the table[] array point to the same byte in this array, which explains the output you get: 5 times the contents of the last line.
You should make a copy of the string you store in the table:
table[tableNumber] = strdup(name);
Here is a completed and modified program:
#include <stdio.h>
#include <string.h>
int main() {
char *table[5] = { NULL, NULL, NULL, NULL, NULL };
char buffer[50];
char *number;
char *name;
int tableNumber;
for (int i = 0; i < 5; i++) {
if (!fgets(buffer, sizeof buffer, stdin))
break;
number = strtok(buffer, "-");
if (number == NULL) {
printf("empty line\n");
continue;
}
name = strtok(NULL, "-\n");
if (name == NULL) {
printf("no name after -\n");
continue;
}
tableNumber = atoi(number);
if (tableNumber < 0 || tableNumber >= 5) {
printf("invalid number: %d\n", tableNumber);
continue;
}
table[tableNumber] = strdup(name);
}
for (int i = 0; i < 5; i++) {
if (table[i])
printf("table %d = %s\n", i, table[i]);
}
for (int i = 0; i < 5; i++) {
free(table[i]);
}
return 0;
}
If your target system does not support strdup(), use this:
#include <stdlib.h>
#include <string.h>
char *mystrdup(const char *s) {
size_t size = strlen(s) + 1;
char *p = malloc(size);
return (p != NULL) ? memcpy(p, s, size) : NULL;
}

The sample code:
Enter message like "sceneNumber.sceneName.sceneID.Update"
For example: 1.Study.12345.Update
#include <stdio.h>
#include <string.h>
#include <conio.h>
char *gSceneTable[13];
char gMessageBuffer[50];
int main()
{
char *sceneNumber;
char *sceneName;
char *sceneID;
char *sceneAction;
int sceneTableNumber;
int check;
int c;
printf("Enter payload for 3 Times\r\n");
while(check != 3)
{
scanf("%s", &gMessageBuffer);
printf("Message is: %s\r\n",gMessageBuffer);
sceneNumber = strtok(gMessageBuffer, ".");
sceneName = strtok(NULL, ".");
sceneID = strtok(NULL, ".");
sceneAction = strtok(NULL, ".");
printf("%s\r\n", sceneNumber);
printf("%s\r\n", sceneName);
printf("%s\r\n", sceneID);
printf("%s\r\n", sceneAction);
if (strcmp(sceneAction, "Update") == 0)
{
sceneTableNumber = atoi(sceneNumber);
gSceneTable[sceneTableNumber] = sceneName;
}
check++;
}
for (c = 0; c < 4; c++)
{
printf("Scene Table: %d ----- %s \r\n", c, gSceneTable[c]);
}
return 0;
}

Related

How to read from the file and write it in the structure? I have a little trouble with my code

I have to write this code, I mean I should read from the file name of students and their mark, and then sort students by the grow of mark. Now I just want to output only mark. I want to display grades using structures. I don't know where the problem is.
text.file
Jon 3
Alina 5
Ron 1
#include <stdio.h>
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdlib.h>
int main()
{
const int N = 3;
int i = 0;
struct student {
char surname[50];
int mark;
};
struct student PI1[N];
char str[50];
const char s[1] = " ";
char* token;
FILE* ptr;
token = strtok(str, s);
ptr = fopen("test.txt", "r");
if (NULL == ptr) {
printf("file can't be opened \n");
}
while (fgets(str, 50, ptr) != NULL){
token = strtok(str, s);
strcpy(PI1[i].surname, token);
token = strtok(NULL, s);
PI1[i].mark = atoi(token);
i++;
}
fclose(ptr);
printf("The marks is:\n");
printf("%d %d %d", PI1[0].mark, PI1[1].mark, PI1[2].mark);
return 0;
}
You need to prevent the program from reading from the file pointer if opening the file fails:
ptr = fopen("test.txt", "r");
if (NULL == ptr) {
perror("test.txt");
return 1; // this could be one way
}
The second argument to strok should be a null terminated string. const char s[1] = " "; only has room for one character. No null terminator (\0). Make it:
const char s[] = " "; // or const char s[2] = " "; or const char *s = " ";
Don't iterate out of bounds. You need to check so that you don't try to put data in PI1[N] etc.
while (i < N && fgets(str, sizeof str, ptr) != NULL) {
// ^^^^^^^^
Check that strok actually returns a pointer to a new token. If it doesn't, the line you've read doesn't fulfill the requirements.
while (i < N && fgets(str, sizeof str, ptr) != NULL) {
token = strtok(str, s);
if(!token) break; // token check
strcpy(PI1[i].surname, token);
token = strtok(NULL, s);
if (token) // token check
PI1[i].mark = atoi(token);
else
break;
i++;
}
You could also skip the strcpy by reading directly into your struct student since char str[50]; has the same length as surname. str should probably be larger though, but for now:
while (i < N && fgets(PI1[i].surname, sizeof PI1[i].surname, ptr) != NULL) {
token = strtok(PI1[i].surname, s);
if(!token) break;
token = strtok(NULL, s);
if (token)
PI1[i].mark = atoi(token);
else
break;
i++;
}
Only print as many marks as you successfully read
printf("The marks are:\n");
for(int idx = 0; idx < i; ++idx) {
printf("%d ", PI1[idx].mark);
}
putchar('\n');

Error when reading strings from CSV (Core Dumped)

I keep getting the same error, I'm new to programming so I'm not so sure if the Syntax is correct.
Every time I run it, it returns Segmentation Fault(core dumped), I'm not even sure If I can open a file with a string (address) instead of the filename in extense.
Also the files I'm reading from are CSV but in txt format.
I'm using C99
#define BUFFER_SIZE 1024
#define TAM_PERGUNTAS 128
struct question{
char category[TAM_PERGUNTAS];
char question[TAM_PERGUNTAS];
char option1[TAM_PERGUNTAS];
char option2[TAM_PERGUNTAS];
char option3[TAM_PERGUNTAS];
char correct[TAM_PERGUNTAS];
};
struct question vec_question[BUFFER_SIZE];
void questions() {
FILE *perguntas;
int numaleat=0;
int num_questions, counter = 0, index, temp_randomizer=0;
char line[BUFFER_SIZE];
char answer[32];
char address[TAM_PERGUNTAS];
address[0] = '\0';
srand(time(NULL));
printf("Digite agora o numero de perguntas desejadas.(MAX 20) : "); //Insert Number of questions
scanf("%d", &num_questions);
printf("\n");
for (counter = 0; counter < num_questions; counter++) {
temp_randomizer = rand() % j; //j Represents the number o CATEGORIES at play and acts as a marker in the SELECTION string
sprintf(address, "%s.txt", SELECTION[temp_randomizer]);
perguntas = fopen(address, "r");
if (perguntas == NULL) {
printf("ERROR OPENING FILE!");
}
index = 0;
while (fgets(line, sizeof(line), perguntas) != NULL) {
strcpy(vec_question[index].category, strtok(line, ";"));
strcpy(vec_question[index].question, strtok(NULL, ";"));
strcpy(vec_question[index].option1, strtok(NULL, ";"));
strcpy(vec_question[index].option2, strtok(NULL, ";"));
strcpy(vec_question[index].option3, strtok(NULL, ";"));
strcpy(vec_question[index].correct, strtok(NULL, ";"));
vec_question[index].correct[strlen(vec_question[index].correct) - 1] = '\0';
index++;
}
fclose(perguntas);
index = 20;
numaleat = rand() % index;
printf("%s : %s\n%s\n%s\n%s",vec_question[numaleat].category,vec_question[numaleat].question,vec_question[numaleat].option1,vec_question[numaleat].option2,vec_question[numaleat].option3);
for (int i = 0; i < num_users; i++) {
printf("\n%s: ", &users[i][20]);
scanf("%s", &answer[32]);
if (answer == vec_question[numaleat].correct)
userspoints[i] += 1;
}
}
}
In general one should assume that functions like strtok can fail.
Sometimes it fails and returns a NULL value. A short record in your input is a likely cause.
Consider using it with a loop, and breaking out of the loop once strtok returns NULL.
I found a simple example here.
#include <string.h>
#include <stdio.h>
int main () {
char str[80] = "This is - www.tutorialspoint.com - website";
const char s[2] = "-";
char *token;
/* get the first token */
token = strtok(str, s);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, s);
}
return(0);
}
Note that it does one strtok to get the first token. That might return NULL in which case the loop doesn't run. If it doesn't return NULL then it prints that token, and asks strtok for the next token. It keeps doing that until strtok returns NULL.

Parsing nmea csv in c++/c for microchip

How can I parse a comma separated char string? I've tried using strtok but I can't get it working.
char str2[] = "$GNRMC,011802.00,A,4104.22420,N,08131.66173,W,0.021,,280218,,,D*78\n";
char *p;
p = strtok(str2, ",");
char *input[8];
int i = 0;
for( i=0;i<8;i++)
{
input[i] = p;
p = strtok(NULL, ",");
}
Ideally I'd like to be able to set a variable to the string. Such as
if (i == 0){
string type = $GNRMC;
}
if (i == 1){
float thisnum = 011802.00
}
etc.
This is being written for a pic so I can't use vectors.
You're upper snippet is working for me, besides two minor issues:
buf should be str2
your array of char pointers is too small to hold all substrings
For the second one, you need to convert your substring to the correct type first.
__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
#define NUM_SUBSTRINGS 13
char str2[] = "$GNRMC,011802.00,A,4104.22420,N,08131.66173,W,0.021,,280218,,,D*78\n";
char *p;
p = strtok(str2, ",");
char * input[NUM_SUBSTRINGS];
int i = 0;
for(i=0; i<NUM_SUBSTRINGS; i++)
{
char *type = NULL;
float thisnum = 0.0;
if (i == 0){
type = p;
}
if (i == 1){
thisnum = strtof(p, NULL);
}
if(p != NULL)
printf("String %s, type: %s, num: %f\n", p, type, thisnum);
input[i] = p;
p = strtok(NULL, ",");
}
return 0;
}

How to split up a string and count how many times a word is used?

while(token != NULL)
{
// for(position = strcspn(str,token); position >= 0;
// position = strcspn(str, token + 1));
// {
// str2[position] = count++;
// }
}
I think I'm having a logic issue with my code. I'm trying to take in a string from user input and return how many times each word was used and only return each word one time. I think my issue is within the section I have commented out but I'm not entirely sure how to fix or change my code.
For example:
Input: Hello, my cat is saying Hello.
Output: Hello 2
my 1
cat 1
is 1
saying 1
I have modified your code and written little differently,
Please have a look.
int main()
{
char haystack[50] = "Hello my cat is saying Hello";
char needle[10];
int i = 0,j = 0,k = 0;
char *ret = NULL;
int cnt = 0;
while(haystack[i] != NULL)
{
if(haystack[i] == ' ')
{
i++;
}
else
{
//Get each sub strings.
while((haystack[i] != ' ') && (haystack[i] != NULL))
{
needle[k++] = haystack[i];
i++;
}
needle[k] = '\0';
printf("The substring is: %s", needle);
//Find how many times the sub string is there in the string
while(strstr(haystack, needle) != NULL)
{
ret = strstr(haystack, needle);
//Once the Substring is found replace all charecter of that substring with space.
for(j=0;j<k;j++)
{
*(ret+j) = ' ';
}
cnt++;//Count the no of times the substrings found.
}
printf("= %d\n",cnt);
cnt = 0;
k = 0;
}
}
return(0);
}
I have not taken care for the special characters, You can modify to take care of those.
So I have used the string "Hello my cat is saying Hello" instead of "Hello, my cat is saying Hello.". Removed the Comma.
Hope this Helps.
To compute how many times a word is present in a string or line you need a structure to preserve all the different words you have and mainly how many times each word is frequent.
My simple approach, without any optimization, is:
#include <stdio.h>
#include <stdlib.h>
struct wordsDetail
{
char word[100];
int freq;
} wordsDetail;
void updateWords(struct wordsDetail s[], int length, char *token)
{
int i;
for (i = 0; i < length && s[i].word[0] != '\0'; i++) {
if (strcmp(s[i].word, token) == 0) {
s[i].freq++;
return;
}
}
strcpy(s[i].word, token);
s[i].freq++;
}
void printResults(struct wordsDetail s[], int length) {
printf("Words\tFreq\n");
for (int i = 0; i <length && s[i].word[0] != NULL; i++) {
printf("%s\t%d\n", s[i].word, s[i].freq);
}
}
int main(void)
{
struct wordsDetail myWords[100];
int wordsDetailLength = sizeof(myWords) / sizeof(wordsDetail);
const size_t line_size = 1024;
char *str = NULL;
int *str2 = NULL;
int i = 0;
char *token;
for (i = 0; i < wordsDetailLength; i++) {
myWords[i].word[0] = '\0';
myWords[i].freq = 0;
}
if ((str = calloc(line_size, sizeof(char))) == NULL) {
printf("error\n");
exit(-1);
}
printf("Input: ");
if (scanf("%[^\n]", str) != 1) {
printf("error\n");
exit(-1);
}
printf("Output: \n");
token = strtok(str, " .,!");
while (token != NULL) {
updateWords(myWords, wordsDetailLength, token);
token = strtok(NULL, " .,!");
}
printResults(myWords, wordsDetailLength);
return 0;
}
A simple result is:
Input: Hello, my cat is saying Hello to my cat.
Output:
Words Freq
Hello 2
my 2
cat 2
is 1
saying 1
to 1

arrays from txt in c (long numbers)

400000000000;499999999999;VISA;
50000000;59999999;MASTERCARD;
67000000;67999999;MAESTRO;
fields: 1. Range Start 2. Range End, 3 Name.
[Start Range] and [End Range] fields can be from 1 to 16 characters (digits) in length.
The program's objective is as follows:
First Request to enter 16-digit card number.
Card number input, verification and processing use char [n] type (Simbol array)
Second:Check for an entry corresponding to the entered card number can be found in a text file if I enter 45000000000 it's between 400000000000 and 499999999999 so i need to put a text in a autput name VISA.
And i can't use long long types... as i undrstand i need to use arrays...
Third Request to enter the amount in the format "nnnn.mm", where nnnn-1 to 4 digits long amount of lats, but mm - 2-digit amount santims.
char input[32]; // = "100;200;first";
char name[10];
int min, max, c, i, k;
FILE *file;
file = fopen("gg.txt","r");
i=0;
while ((c=getc(file))!= EOF)
{
k=(int)c;
input[i]=k;
i++;
}
char* result = NULL;
char delims[] = ";";
result = strtok(input, delims);
// atoi() converts ascii to integer.
min = atoi(result);
result = strtok(NULL, delims);
max = atoi(result);
result = strtok(NULL, delims);
strcpy(name, result);
printf("Min=%d, Max=%d, Name=%s\n", min, max, name);
printf("input=%s\n",input);
printf("%d\n",i);
getch();
return 0;
this code given me by varunl works vith smal numbers ( the containing of gg.txt file is: 100;200;first), but a need smt else, enybody, can help me?
The trick is in padding the numbers to 16 digits, so you can compare them as strings. So if you read this:
67000000;67999999;MAESTRO;
in reality you have to consider it like this:
0000000067000000;0000000067999999;MAESTRO;
The same for the user input.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void FindCCType(const char *pnumber);
int main(int argc, char *argv[])
{
FindCCType("67000001");
return 0;
}
#define MAXLENGTH 16
char* PadLeft(const char *pnumber)
{
char *pnumber2 = (char*)malloc(MAXLENGTH + 1);
size_t len = strlen(pnumber);
if (len > MAXLENGTH)
{
/* Too many digits in credit card number */
exit(1);
}
strcpy(pnumber2 + MAXLENGTH - len, pnumber);
char *pbegin = pnumber2, *plast = pnumber2 + MAXLENGTH - len;
while (pbegin < plast)
{
*pbegin = '0';
pbegin++;
}
return pnumber2;
}
void FindCCType(const char *pnumber)
{
printf("Input: %s\n", pnumber);
char *pnumber2 = PadLeft(pnumber);
FILE *file = fopen("gg.txt","r");
char pline[1000];
while (fgets(pline, sizeof(pline), file) != NULL)
{
if (strlen(pline) + 1 == sizeof(pline))
{
/* Line too much long */
exit(2);
}
char *pmin = strtok(pline, ";");
char *pmax = strtok(NULL, ";");
char *pname = strtok(NULL, ";");
printf("Min: %s, Max: %s, Name: %s", pmin, pmax, pname);
char *pmin2 = PadLeft(pmin);
char *pmax2 = PadLeft(pmax);
if (strcmp(pnumber2, pmin2) >= 0 && strcmp(pnumber2, pmax2) <= 0)
{
printf(" ** FOUND **\n");
free(pmin2);
free(pmax2);
break;
}
printf(" ** NO GOOD **\n");
free(pmin2);
free(pmax2);
}
fclose(file);
free(pnumber2);
}

Resources