split array of char with delimiter '#' and save in another array - c

I have a problem. I receive a response from a server as an array of chars. Ex: 555#200#. I split the array into 555 and 200 because that is my command. I want to save that command to another array but I get bad results. Here's my code:
void READ_FROM_SERVER(void) {
int read_vkluci = read(sock_descriptor, read_from_server, sizeof(read_from_server));
if (read_vkluci < 0)
printf("Failed reading bytes from server\n");
printf(" %s \n", read_from_server);
if(read_vkluci>0){
char** tokens;
printf("naredbi=%s \n\n", read_from_server);
tokens = str_split(read_from_server, '#');
if (tokens){
int i;
for (i = 0; *(tokens + i); i++){
printf("naredba=%s\n", *(tokens + i));
naredbi_odelno[i]= *(tokens + i);
printf("naredba_odelno=%s\n", naredbi_odelno[i]);
brojnacomandi++;
//free(*(tokens + i));
}
printf("\n");
//free(tokens);
}
}
int p;
for(p=0;p<brojnacomandi;p++){
if (naredbi_odelno[p]==201) {
nadvoresna_komanda = VKLUCI;
printf("VKLUCEN UVLEKUVAC!!!!");
}
if (naredbi_odelno[p]==200) {
nadvoresna_komanda = ISKLUCI;
printf("ISLKUCEN UVLEKUVAC!!!!");
}
if (naredbi_odelno[p]==96) {
printf("TCP_CONN_OK!!!\n");
}
if (naredbi_odelno[p]==211) {
makeTXpaket(STACK_1);
p_tx_buffer_ = &tx_buffer[1];
nbytes = write(fd, tx_buffer, *p_tx_buffer_);
if (nbytes != tx_buffer[1]) {
/* problem! */
printf("error writing on serial port!!!");
}
printf("PRIMAM....\n");
isprateno=0;
}
if (naredbi_odelno[p]==210) {
makeTXpaket( RETURN);
p_tx_buffer_ = &tx_buffer[1];
nbytes = write(fd, tx_buffer, *p_tx_buffer_);
if (nbytes != tx_buffer[1]) {
/* problem! */
printf("error writing on serial port!!!");
}
printf("VRAKAM....\n");
isprateno=0;
}
// else {
// printf("TCP_NOT_OK!!!!\n");
// close(sock_descriptor);
// CONECT_T0_SERVER();
// }
Clean_read_from_server_buff();
Clean_naredbi_odelno();
}
}
char** str_split(char* a_str, const char a_delim){
char** result = 0;
size_t count = 0;
char* tmp = a_str;
char* last_comma = 0;
/* Count how many elements will be extracted. */
while (*tmp){
if (a_delim == *tmp){
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = malloc(sizeof(char*) * count);
if (result){
size_t idx = 0;
char* token = strtok(a_str, "#");
while (token){
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, "#");
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
The server sends me only 555#, but I get in naredba_odelno bad result! Any idea why that is happening?
How do I make naredba_odelno = naredba because naredba is good!
output:
naredbi=555#
naredba=555
naredbi_odelno= ...... bad results why?

My first guess is that you're reading off the end of the input data. Note that read does not nul-terminate the string, so your printf statement is immediately broken.
Try this:
int read_vkluci = read(sock_descriptor, read_from_server, sizeof(read_from_server)-1);
and this
read_from_server[read_vkluci] = '\0';
printf("naredbi=%s \n\n", read_from_server);
BTW, sizeof(read_from_server) will only work correctly if read_from_server is an array type. If it's a pointer to a buffer then that's broken too.

Related

Copying specific number of characters from a string to another

I have a variable length string that I am trying to divide from plus signs and study on:
char string[] = "var1+vari2+varia3";
for (int i = 0; i != sizeof(string); i++) {
memcpy(buf, string[0], 4);
buf[9] = '\0';
}
since variables are different in size I am trying to write something that is going to take string into loop and extract (divide) variables. Any suggestions ? I am expecting result such as:
var1
vari2
varia3
You can use strtok() to break the string by delimiter
char string[]="var1+vari2+varia3";
const char delim[] = "+";
char *token;
/* get the first token */
token = strtok(string, delim);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
token = strtok(NULL, delim);
}
More info about the strtok() here: https://man7.org/linux/man-pages/man3/strtok.3.html
It seems to me that you don't just want to want to print the individual strings but want to save the individual strings in some buffer.
Since you can't know the number of strings nor the length of the individual string, you should allocate memory dynamic, i.e. use functions like realloc, calloc and malloc.
It can be implemented in several ways. Below is one example. To keep the example simple, it's not performance optimized in anyway.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
char** split_string(const char* string, const char* token, int* num)
{
assert(string != NULL);
assert(token != NULL);
assert(num != NULL);
assert(strlen(token) != 0);
char** data = NULL;
int num_strings = 0;
while(*string)
{
// Allocate memory for one more string pointer
char** ptemp = realloc(data, (num_strings + 1) * sizeof *data);
if (ptemp == NULL) exit(1);
data = ptemp;
// Look for token
char* tmp = strstr(string, token);
if (tmp == NULL)
{
// Last string
// Allocate memory for one more string and copy it
int len = strlen(string);
data[num_strings] = calloc(len + 1, 1);
if (data[num_strings] == NULL) exit(1);
memcpy(data[num_strings], string, len);
++num_strings;
break;
}
// Allocate memory for one more string and copy it
int len = tmp - string;
data[num_strings] = calloc(len + 1, 1);
if (data[num_strings] == NULL) exit(1);
memcpy(data[num_strings], string, len);
// Prepare to search for next string
++num_strings;
string = tmp + strlen(token);
}
*num = num_strings;
return data;
}
int main()
{
char string[]="var1+vari2+varia3";
// Split the string into dynamic allocated memory
int num_strings;
char** data = split_string(string, "+", &num_strings);
// Now data can be used as an array-of-strings
// Example: Print the strings
printf("Found %d strings:\n", num_strings);
for(int i = 0; i < num_strings; ++i) printf("%s\n", data[i]);
// Free the memory
for(int i = 0; i < num_strings; ++i) free(data[i]);
free(data);
}
Output
Found 3 strings:
var1
vari2
varia3
You can use a simple loop scanning the string for + signs:
char string[] = "var1+vari2+varia3";
char buf[sizeof(string)];
int start = 0;
for (int i = 0;;) {
if (string[i] == '+' || string[i] == '\0') {
memcpy(buf, string + start, i - start);
buf[i - start] = '\0';
// buf contains the substring, use it as a C string
printf("%s\n", buf);
if (string[i] == '\0')
break;
start = ++i;
} else {
i++;
}
}
Your code does not have any sense.
I wrote such a function for you. Analyse it as sometimes is good to have some code as a base
char *substr(const char *str, char *buff, const size_t start, const size_t len)
{
size_t srcLen;
char *result = buff;
if(str && buff)
{
if(*str)
{
srcLen = strlen(str);
if(srcLen < start + len)
{
if(start < srcLen) strcpy(buff, str + start);
else buff[0] = 0;
}
else
{
memcpy(buff, str + start, len);
buff[len] = 0;
}
}
else
{
buff[0] = 0;
}
}
return result;
}
https://godbolt.org/z/GjMEqx

Strtok() not splitting the array properly

I was trying to split the array I received as an argument in a function using strtok() and it simply don't work as expected.
For example I receive this string : "ls -l" and I got only "ls".
Furthermore , I want to store the tokens into an array of strings.
Here is what I have done so far:
int mysystem(char *s) {
int i;
char *tok , *aux;
int conta = 0;
int pid, status;
int j = 0;
tok = strtok(s , " ");
while (tok != NULL) {
tok = strtok(NULL, s);
conta++;
}
char *store[conta];
i = 0;
aux = strtok(s ," ");
while (aux != NULL) {
store[i] = aux;
aux = strtok(NULL, s);
i++;
}
pid = fork();
if (pid == 0)
execvp(store[0], store);
while (j != conta) {
wait (&status);
j++;
}
return 0;
}
This is the main of where I'm passing the string to my function :
int main(int args, char **arg) {
int i;
int s;
int f = 0;
if (args >= 2) {
int length = 0;
for (i = 1; i < args; ++i) {
length += strlen(arg[i]);
}
char *output = (char*)malloc(length + 1);
char *dest = output;
i = 1;
while (i < args) {
dest = strcat (dest,arg[i]);
i++;
if (i < args) {
dest = strcat (dest," ");
}
}
dest = strcat(dest, "\0");
s = mysystem(dest);
free(output);
return s;
}
}
strtok modifies the string, so you can't run it twice on the same string. s has been converted to a series of strings separated by NUL characters. Change to using an array which is "long enough" and just go through s once.

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

fgets giving me a segfault when passing only spaces

I am trying to make a shell and one of the conditions i am looking out for is when the user enters a bunch of spaces. However, I get a segfault from fgets when I input any number of spaces in the terminal. It can be one space, or it can be a whole bunch of them followed by a random character. I keep getting a segfault.
Development:
I noticed that I don't get a segfault when I remove my tokenize function. Why would this be the case?
Here's my code:
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
/* Initialize variables and methods */
int status;
int i;
int one_nonspace = -1;
int on = 1;
char input[101];
char temp[101];
char* tokenized;
char operators[3] = {'>', '<', '|'};
char** tokens;
void getInput(char *prmpt, char *buff){
printf(">:");
fgets(buff, 101, stdin); //segfault here when input spaces.
/*printf("works!");*/
if(one_nonspace != -1){
printf("spaces");
memcpy( temp, &buff[i], (101-i) );
temp[100] = '\0';
}
if(buff[strlen(buff) -1] != '\n'){
int over = 0;
while(fgetc(stdin) != '\n')
over++;
if(over>0)
{
printf("Command is over 100 characters. Please try again\n");
status = 1;
}
}
else{
buff[strlen(buff) - 1] = '\0';
status = 0;
}
}
char** tokenize(char* a_str)
{
char** result = 0;
size_t count = 0;
char* tmp = a_str;
char* last = 0;
char delim[2];
delim[0] = ' ';
delim[1] = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (' ' == *tmp)
{
count++;
last = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = malloc(sizeof(char*) * count);
if (result)
{
size_t idx = 0;
char* token = strtok(a_str, delim);
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, delim);
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
/* Create a parser Feb 2*/
int main(int argc, char **argv){
while(on){
getInput(">: ", input);
tokenized = input;
if(status == 0){
/*printf("%s\n", input);*/
}
/*Split the line into tokens*/
if(input[0] != ' ')
tokens = tokenize(tokenized);
/*if tokens[0] == 'exit', then quit.
*/
if(strcmp(*(tokens),"exit") == 0){
break;}
/*2/3 Now we need to do something with the split up tokens*/
/*printf("input after token: %s\n", input);*/
/*Free the tokens at the end!!! Remember this!*/
if (tokens)
{
int i;
for (i = 0; *(tokens + i); i++)
{
printf("%s\n", *(tokens + i));
free(*(tokens + i));
}
free(tokens);
}
}
return 0;
}
Here's the problem:
/*Split the line into tokens*/
if(input[0] != ' ')
tokens = tokenize(tokenized);
/*if tokens[0] == 'exit', then quit.
*/
if(strcmp(*(tokens),"exit") == 0){
break;}
When input begins with a space character, you skip the tokenize function and attempt to dereference tokens - a NULL pointer.
Edit: you are trying to debug with print statements and that is a valid method, but remember to flush the buffers or you won't get an accurate idea of where the problem is if the crash happens before there's any output. You can flush them explicitly with fflush or simply use newline characters if you're on a terminal, as they are usually line buffered.

curl not grabbing page on second pass instead returning an empty string?

I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
char * return_next(char *link, int rand_flag);
char* strip_parens(char* string);
char* strip_itals(char* string);
char* strip_tables(char* string);
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t
WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)data;
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
if (mem->memory == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
exit(EXIT_FAILURE);
}
memcpy(&(mem->memory[mem->size]), ptr, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
int main(void)
{
char *page = malloc(1000);
page = strcpy(page, "http://en.wikipedia.org/wiki/Literature");
char *start = malloc(1000);
start = strcpy(start, page);
printf("%s\n\n", page);
int i = 0, rand_flag = 0;
while(strcmp(page, "http://en.wikipedia.org/wiki/Philosophy")){
i++;
page = return_next(page, rand_flag);
printf("deep: %d, %s\n\n", i, page);
rand_flag = 0;
}
printf("start link: %s, is %d clicks from philosophy", start, i);
return 0;
}
char * return_next(char *link, int rand_flag){
CURL *curl_handle;
struct MemoryStruct chunk;
chunk.memory = malloc(1);
chunk.size = 0;
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, link);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1");
if(rand_flag){
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
}
curl_easy_perform(curl_handle);
curl_easy_cleanup(curl_handle);
char *theString = malloc(strlen(chunk.memory)+1);
char *theString1 = malloc(strlen(theString) + 1);
theString = strstr(chunk.memory, "div id=\"body");
theString1 = strip_tables(theString);
if(chunk.memory)
free(chunk.memory);
theString = strstr(theString1, "<p>");
theString1 = strip_itals(theString);
theString = strip_parens(theString1);
curl_global_cleanup();
return theString;
}
char* strip_parens(char* string) {
long len = strlen(string);
char* result = malloc(len + 1);
int num_parens = 0;
int i, j = 0;
for(i=0; i < len; i++) {
char c = string[i];
if(c == '(') {
num_parens++;
}
else if(c == ')' && num_parens > 0) {
num_parens--;
}
else if(num_parens == 0) {
if(c == '<'){
if (string[i+1] == 'a'){
if (string[i+2] == ' ') {
if(string[i+3] == 'h'){
i = i+9;
for(;string[i] != '"'; i++){
result[j] = string[i];
j++;
}
result[j] = '\0';
len = strlen("http://en.wikipedia.org");
char *final = malloc(j+len);
final = strcpy(final, "http://en.wikipedia.org");
return strcat(final, result);
}
}
}
}
}
}
result[j] = '\0';
return result;
}
char* strip_itals(char* string) {
long len = strlen(string);
char* result = malloc(len + 1);
int inside = 0;
int i, j = 0;
for(i=0; i < len; i++) {
//printf(".%d, %c, %d\n", i, string[i], inside);
char c = string[i];
if(c == '<' && inside == 0) {
if (string[i+1] == 'i'){
if (string[i+2] == '>') {
inside++;
i = i+2;
}
}
}
else if(c == '<' && inside > 0) {
//printf("first if\n");
if (string[i+1] == '/'){
if (string[i+2] == 'i') {
inside--;
i=i+3;
}
}
}
if(inside == 0) {
result[j] = c;
j++;
}
}
result[j] = '\0';
return result;
}
char* strip_tables(char* string) {
//printf("%s\n", string);
long len = strlen(string);
//long len = 1000000;
char* result = malloc(len + 1);
int inside = 0;
int i, j = 0;
for(i=0; i < len; i++) {
//printf(".%d, %c, %d\n", i, string[i], inside);
char c = string[i];
if(c == '<' && inside == 0) {
if (string[i+1] == 't'){
if (string[i+2] == 'a') {
if (string[i+3] == 'b') {
if (string[i+4] == 'l') {
inside++;
i = i+4;
}
}
}
}
}
else if(c == '<' && inside > 0) {
//printf("first if\n");
if (string[i+1] == '/'){
if (string[i+2] == 't') {
if (string[i+3] == 'a') {
if (string[i+4] == 'b') {
if (string[i+5] == 'l') {
inside--;
i=i+7;
}
}
}
}
}
}
if(inside == 0) {
result[j] = c;
j++;
}
}
result[j] = '\0';
return result;
}
That given a link to a wiki article will return the first link back, then in main I loop over this function till I arrive at a specified article. I ran from some random article and discovered when it passes over "Literature" it gets "Art" as the next page but when it goes to search Art curl returns a blank string- if i print("%s", chunk.memory) after the call I get (null). If I manually force the function to start at art it works fine, trailing all the way to philosophy. For the life of me I cant see any differences... I put some diagnostic printfs in and got the following-
this is the address ~> !http://en.wikipedia.org/wiki/Art!, rand flag = 0
With the link inbetween the exlamation marks, so I know it's parsing the link back properly, and rand_flag is always set to 0 at the moment.
Any tips, pointers or solutions much appreciated.
It is not generally possible to say anything about a program if all you have is an uncompilable piece of code. So I'm going to give some generic recommendations.
Check return values of your functions.
Set up callbacks to libcurl so that you can print every byte that goes in and out with a flip of a switch (much like curl -v does — look at its source if you need guidance).
Sniff your network traffic.
If you see that a request is not sent at all, or that it's sent but no data is returned, you have narrowed your problem a bit.
The code is complete borked and will not work. Let me illustrate by snipping a piece of the code and comment:
char *theString =
malloc(strlen(chunk.memory)+1);
char *theString1 =
malloc(strlen(theString) + 1);
Doing strlen(theString) will call strlen() on a pointer that points to uninitialized memory. Can be anything. And then you allocate that size and put in a second pointer...
theString = strstr(chunk.memory, "div
id=\"body");
... and yet you assign 'theString' again to a position within the 'chunk.memory' memory area.
theString1 = strip_tables(theString);
And you assign 'theString1' again to some position within 'theString'.
You've now leaked your two mallocs.
if(chunk.memory)
free(chunk.memory);
And look, you now freed the data your two pointers are pointing to. They now point to garbage.
theString = strstr(theString1, "");
... and now you search in the data you already freed.
Do I need to say more?

Resources