Dividing up a char array to different values in struct - c

Through a tcp socket I get a string like this: "SmallTitle fromhost 9595".
Upon reciving it I would like to divide it in to a struct so it's easier to work with.
This is what I have come up with. But there are problems. 1 it is nasty. 2 When printing the struct in the end i recieve garbage output after the string. See output example at the bottom. Should not printf stop at '\0'? Then it might be missing such.
struct recieved {
char what[50];
char from[50];
int value;
};
int main(int argc, char const *argv[]) {
struct recieved leaderRec;
char *word;
char buf[] = "leadervalue host 9569"; //Example recieved input from socket.
word = (char *) malloc(sizeof(char) * 50);
int i = 0;
int count = 1;
do{
if((buf[i] == ' ') || (buf[i+1] == '\0')){
//End of word
//word[strlend(word)+1] = '\0';
//printf("%s\n", word);
if(count == 3){
//The value is here
//get the last number
strncat(word,&buf[i], 1);
leaderRec.value = atoi(word);
//printf("%d\n", value);
}
if(count == 1)
strncpy(leaderRec.what, word, strlen(word));
else if(count == 2)
strncpy(leaderRec.from, word, strlen(word));
free(word);
word = (char *) malloc(sizeof(char) * 50);
count++;
}
else {
//printf("%d\n",i );
//printf("%s\n", &buf[i]);
strncat(word,&buf[i], 1);
}
//printf("%s", &buf[i]);
//printf("%d -", i);
i++;
} while(buf[i] != '\0');
printf("%s\n", leaderRec.what);
printf("%s\n", leaderRec.from);
printf("%d\n", leaderRec.value);
return 0;
}
Output:
leadervalue
host__vdso_get
9569
Any better ways to do this?
How would I avoid the garbage output at the second print in the example output?

But there are problems. 1 it is nasty. 2 When printing the struct in
the end i recieve garbage output after the string.
The "garbage" prints, as have been noted in the comments, are because you are not properly null terminating your strings. For instance, you are not initializing word to an empty string (single null character) before calling strncat.
Any better ways to do this?
Most certainly. I'd suggest using strtok as so:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct received {
char what[50];
char from[50];
int value;
};
int main(void)
{
char buf[] = "leadervalue host 9569";
struct received leaderRec;
/* Initialize leaderRec here */
memset(&leaderRec, 0, sizeof(leaderRec));
char *s = strdup(buf);
char *p = strtok(s, " ");
if (p != NULL) {
strncpy(leaderRec.what, p, sizeof(leaderRec.what));
p = strtok(NULL, " ");
}
if (p != NULL) {
strncpy(leaderRec.from, p, sizeof(leaderRec.from));
p = strtok(NULL, " ");
}
if (p != NULL) {
leaderRec.value = atoi(p);
}
free(s);
printf("%s %s %d\n", leaderRec.what, leaderRec.from, leaderRec.value);
return 0;
}

Related

Extracting the first two words in a sentence in C without pointers

I am getting used to writing eBPF code as of now and want to avoid using pointers in my BPF text due to how difficult it is to get a correct output out of it. Using strtok() seems to be out of the question due to all of the example codes requiring pointers. I also want to expand it to CSV files in the future since this is a means of practice for me. I was able to find another user's code here but it gives me an error with the BCC terminal due to the one pointer.
char str[256];
bpf_probe_read_user(&str, sizeof(str), (void *)PT_REGS_RC(ctx));
char token[] = strtok(str, ",");
char input[] ="first second third forth";
char delimiter[] = " ";
char firstWord, *secondWord, *remainder, *context;
int inputLength = strlen(input);
char *inputCopy = (char*) calloc(inputLength + 1, sizeof(char));
strncpy(inputCopy, input, inputLength);
str = strtok_r (inputCopy, delimiter, &context);
secondWord = strtok_r (NULL, delimiter, &context);
remainder = context;
getchar();
free(inputCopy);
Pointers are powerful, and you wont be able to avoid them for very long. The time you invest in learning them is definitively worth it.
Here is an example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
Extracts the word with the index "n" in the string "str".
Words are delimited by a blank space or the end of the string.
}*/
char *getWord(char *str, int n)
{
int words = 0;
int length = 0;
int beginIndex = 0;
int endIndex = 0;
char currentchar;
while ((currentchar = str[endIndex++]) != '\0')
{
if (currentchar == ' ')
{
if (n == words)
break;
if (length > 0)
words++;
length = 0;
beginIndex = endIndex;
continue;
}
length++;
}
if (n == words)
{
char *result = malloc(sizeof(char) * length + 1);
if (result == NULL)
{
printf("Error while allocating memory!\n");
exit(1);
}
memcpy(result, str + beginIndex, length);
result[length] = '\0';
return result;
}else
return NULL;
}
You can easily use the function:
int main(int argc, char *argv[])
{
char string[] = "Pointers are cool!";
char *word = getWord(string, 2);
printf("The third word is: '%s'\n", word);
free(word); //Don't forget to de-allocate the memory!
return 0;
}

How to shift letters to the right or left?

I am given a file with a string, for example "The United States was founded in *1776*". What I cannot figure out is how to shift letters one space to the left or right and have the letters wrap around. I am able to shift the letters from an a to b but not change its location within the word.
Example of this output would be:
"heT
nitedU
tatesS
asw
oundedf
ni
1776**"
In C, strings are stored as an array of chars in memory. Unlike C++ vectors, you can not insert or remove element within the array, you can only access their value or change their value.
If you declare a C string as follows:
char *myStr = "Fred";
It will be stored in memory as a five character array with the 5th character being the zero value which terminates a C string:
myStr[0] = 'F'
myStr[1] = 'r'
myStr[2] = 'e'
myStr[3] = 'd'
myStr[4] = 0
You need to design a for loop that copies each array element to the one before, while remembering that you need to save the one you are about to overwrite. In this example, it should result in the following copy operations being performed:
len = strlen(myStr);
saveCh = myStr[0];
myStr[0] = myStr[1];
myStr[1] = myStr[2];
myStr[2] = myStr[3];
myStr[3] = saveCh;
So now your job is to create a for loop that does that for any C string of any length.
So to rotate the chars within a C string to the left, you need to copy each char in the array at index i to previous array element i-1. The tricky part is to handle the wrap around properly when i=0 (in this example, you want to copy myStr[0] to myStr[3]. Now do that with a for loop.
You need to also understand that the last character of any C string is the null character (value zero), which terminates a C string. If you modify that element in the array, then your string will break. That is why saveCh is copied to myStr[3] and not to myStr[4].
void rotateStrLeftOneChar(char *myStr) {
// Always check for error and special cases first!
// If myStr is a NULL pointer, do nothing and exit
// If myStr is less than 2 chars, nothing needs to be done too.
if ((myStr != NULL) && (strlen(myStr)>1)) {
int len = strlen(myStr);
char saveCh = myStr[0];
int i = 0;
// Copy each char at index i+1 left to index i in the array
for(i=0; i<len-2; i++)
myStr[i] = myStr[i+1];
// The last character is special and is set to saveCh
myStr[len-1] = saveCh;
}
}
If you just need to output the letters to shift to the left and don't want to change original input then you can do:
#include <stdio.h>
#include <string.h>
void shiftletters(char * input, int i);
int main () {
char input[256];
int shift;
printf("Enter input : ");
scanf("%[^\n]s", input);
printf("Number of shifts : ");
scanf("%d", &shift);
shiftletters(input, shift);
return 0;
}
void shiftletters(char * input, int numshifts)
{
char str[256] = {'\0'};
char * delim = " \t";
char * pch = NULL;
int j, k, len, shifts;
if (input == NULL)
{
printf ("Invalid input\n");
return;
}
strcpy (str, input);
pch = strtok (str, delim);
while (pch != NULL)
{
len = strlen (pch);
if ((numshifts == len) || (len == 1))
{
printf ("%s\n", pch);
pch = strtok (NULL, delim);
continue;
}
if (len < numshifts)
shifts = numshifts % len;
else
shifts = numshifts;
for(j=shifts; j<len; j++)
printf("%c", pch[j]);
for(k=0; k<shifts; k++)
printf("%c", pch[k]);
printf("\n");
pch = strtok (NULL, delim);
}
}
The output of the program:
Enter input : The United States was founded in *1776*
Number of shifts : 1
heT
nitedU
tatesS
asw
oundedf
ni
1776**
like this
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum { L = -1, R = 1};
char *rotate(char word[], int dir){
size_t len = strlen(word);
char *temp = malloc(len + 1);
if(!temp){
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(temp, word);
for(char *src = temp; *src; ++src, ++dir){//or use memmove
word[(dir+len)%len] = *src;
}
free(temp);
return word;
}
int main(int argc, char *argv[]) {
FILE *fp = fopen("data.txt", "r");
if(fp == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
if(argc < 2){
fprintf(stderr, "Usage %s L|R...\n", argv[0]);
exit(EXIT_FAILURE);
}
char word[64];
while(fscanf(fp, "%63s", word)==1){
for(char *shift = argv[1]; *shift; ++shift){
int dir = *shift == 'L' ? L : R;
rotate(word, dir);
}
printf("%s\n", word);
}
fclose(fp);
}
using memmove version
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum { L = -1, R = 1};
char *rotate1(char word[], int dir){
size_t len = strlen(word);
if(len > 2){
char temp;
if(dir == L){
temp = word[0];
memmove(word, word+1, len-1);
word[len-1] = temp;
} else if(dir == R){
temp = word[len-1];
memmove(word+1, word, len-1);
word[0] = temp;
}
}
return word;
}
int main(int argc, char *argv[]) {
FILE *fp = fopen("data.txt", "r");
if(fp == NULL){
perror("fopen");
exit(EXIT_FAILURE);
}
if(argc < 2){
fprintf(stderr, "Usage %s L|R...\n", argv[0]);
exit(EXIT_FAILURE);
}
char word[64];
while(fscanf(fp, "%63s", word)==1){
for(char *shift = argv[1]; *shift; ++shift){
int dir = *shift == 'L' ? L : R;
rotate1(word, dir);
}
printf("%s\n", word);
}
}

Sorting string lexicographically in c

I want to sort words of a string in lexicographical order.
For Example:
I have a string: I am Apple
Output should be: am Apple I
Problem (output):
enter the string
hello shamsh
the sorted array:
hello
It's not sorting the string and whole string is not being shown in the output, can anyone help me out here. Thanks!
Program code:
#include<stdio.h>
#include<string.h>
void main()
{
char a[25][25],t[25];
char s[200];
char * pch;
int count = 0;
int i,j ,n;
printf("enter the string\n");
gets(s);
pch = strtok (s," ,.-");
for (i = 0;s[i] != '\0';i++)
{
if (s[i] == ' ')
count++;
}
count=count+1;
i=0;
while(pch != NULL)
{
strcpy(a[i],pch);
pch = strtok (NULL, " ,.-");
i++;
}
for(i=0;i<count-1;i++)
{
for(j=i+1;j<count;j++)
{
if(strcmp(a[i],a[j])>0)
{
strcpy(t,a[i]);
strcpy(a[i],a[j]);
strcpy(a[j],t);
}
}
}
printf("the sorted array:\n");
for(i=0;i<count;i++)
printf("%s\n",a[i]);
}
If you try to print your string after you pch = strtok (s," ,.-"), you'll notice that your string is broken up. That's because strtok() is destructive and breaks up the string into tokens so you need to count the number of white spaces before calling strtok():
printf("enter the string\n");
gets(s);
for (i = 0;s[i] != '\0';i++)
{
if (s[i] == ' ')
count++;
}
count=count+1;
i=0;
pch = strtok (s," ,.-");
Also like Weather Vane said, don't use gets(), use fgets() instead oand remove the '\n' from end of the string afterwards. Also you can use realloc() to assign more memory to a dynamic array instead of using a static array since you wouldn't know the number of words in a string beforehand.
#include <stdlib.h>
#include<stdio.h>
#include<string.h>
void main()
{
char** a = NULL;
char t[25];
char s[512];
char * pch;
int count = 0;
int i,j ,n;
printf("enter the string\n");
if(fgets(s,512, stdin)==NULL)
{
printf("failed to read string\n");
exit(-1);
}
/*remove '\n' from end of the string*/
char *pos;
if ((pos=strchr(s, '\n')) != NULL)
*pos = '\0';
pch = strtok(s, " ,.-");
while(pch)
{
a = realloc(a, sizeof(char*)*++count);
if(a==NULL)
{
perror("failed to allocate memory\n");
exit(-1);
}
a[count-1] = pch;
pch = strtok(NULL, " ,.-");
}
for(i=0;i<count;i++)
printf("%d: %s\n", i, a[i]);
///...compare array
Use qsort() for this sort of thing.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 0x100
int strcmp_wrapper(const void *a, const void *b) {
return strcmp(*(const char **)a, *(const char **)b);
}
int main () {
char buffer[BUF_SIZE], *tokens[BUF_SIZE / 2 + 1];
int i = 0, j = 0;
printf("Enter a string: ");
fgets(buffer, BUF_SIZE, stdin);
tokens[0] = strtok(buffer, " ,.-\n");
while ((tokens[++i] = strtok(NULL, " ,.-\n")));
qsort(tokens, i, sizeof(tokens[0]), strcmp_wrapper);
while (j < i)
printf("%s\n", tokens[j++]);
return 0;
}
below is a compact working way of doing what you want. It prints the words of each line, sorted and separated by one space, without repeating words being repeated (if you want them repeated for sure you will be able to touch the program to make it work)
$ cat pru799.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DELIMITERS " \t\n,.-()&%$\"\'[]{}+-*/;:##|!\\<>=?"
#define LINE_SIZE 1024
#define MAX_WORDS 256
int compare(const char **p, const char **q)
{
return strcmp(*p, *q);
}
int main()
{
char line[LINE_SIZE];
char *words[MAX_WORDS];
int n_words;
while (fgets(line, sizeof line, stdin)) { /* while not eof */
char *p;
int i;
/* first get the words */
n_words = 0;
for (p = strtok(line, DELIMITERS); p; p = strtok(NULL, DELIMITERS)) {
if (strlen(p) == 0) continue; /* word is zero length */
if (n_words >= MAX_WORDS) {
fprintf(stderr, "MAX_WORDS(%d) exceeded\n", MAX_WORDS);
exit(EXIT_FAILURE);
}
words[n_words++] = p;
} /* for */
/* now we have all the words in the array of strings words, sort it */
qsort(words, n_words, sizeof words[0], (int(*)(const void *, const void *))&compare);
/* now print the words */
for (i = 0; i < n_words; i++) {
if (i) { /* all but the first one */
/* don't repeat words */
if (!strcmp(words[i], words[i-1]))
continue;
printf(" "); /* print a space between words */
}
printf("%s", words[i]);
}
printf("\n");
} /* while */
} /* main */

How to get a pointer back from a void function after it iterates through a string pointer

I'm trying to write a code that goes through a given string using a pointer to parse it.
The original code I wrote worked fine but it was... redundant so I tried making it into a function call to make it more concise. Here is what i have:
char inputArray[300];
char buffer[300];
char username[100];
char password[100];
char name[100];
int i=0;
void repeat(char *to)
{
while(*to!='=')
{
to++;
}
}
void array(char *mm,char *tt)
{
i=0;
while(*tt!='+')
{
mm[i]=*tt;
tt++;
i++;
}
}
int main()
{
printf("give me the shit in this fashion: username=?+password=?+real=?\n");
scanf("%s",inputArray);
strcpy(buffer,inputArray);
char *tok=buffer;
repeat(tok);
tok++;
array(username,tok);
repeat(tok);
tok++;
array(password,tok);
tok++;
repeat(tok);
tok++;
array(name,tok);
}
For some reason it won't give me back the pointer array tok where it left off from the previous function call. why is that? it acts as if after calling it the pointer starts back from the beginning.
Functions receive copies of their arguments. Original arguments remain unaffected.
Giving something back has a special syntax in C: the return statement. Thus
char* repeat (char *to) // <- this function gives back a char*
{
while (*to != '=')
{
to++;
}
return to; // <- giving something back
}
Call it like this:
tok = repeat(tok);
Treat array in the same fashion.
Note 1, this function will result in *undefined behaviour if the string doesn't contain '='.
Note 2, it is also possible to pass a pointer to tok as the other answer suggests, but for sake of clarity it is only recommended to use this style when you need to return more than one thing from a function.
just change your repeat to this:
void repeat(char **to) {
while (**to != '=') {
(*to)++;
}
}
and call it like this:
repeat(&tok);
and always check for errors:
if (scanf("%299s", inputArray) != 1){
printf("incorrect input\n");
return 1;
}
and your sample code (and add check for errors in array and repeat to not go out of bounds):
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
char inputArray[300];
char buffer[300];
char username[300];
char password[300];
char name[300];
int i = 0;
void repeat(char **to) {
while (**to != '=') {
(*to)++;
}
}
void array(char *mm, char *tt){
i = 0;
while (*tt != '+') {
mm[i] = *tt;
tt++;
i++;
}
}
int main() {
printf("give me the shit in this fashion: username=?+password=?+real=?\n");
if (scanf("%299s", inputArray) != 1){
printf("incorrect input\n");
return 1;
}
inputArray[299] = 0;
strcpy(buffer, inputArray);
char *tok = buffer;
repeat(&tok);
tok++;
array(username, tok);
repeat(&tok);
tok++;
array(password, tok);
tok++;
repeat(&tok);
tok++;
array(name, tok);
}
and you may use this to not go out of bounds:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
char* read_str(char *src, char *dst){
char *p, *q;
p = src;
while (*p != 0 && *p != '=') p++;
if (*p == 0) {
*dst = 0;
return NULL; // '=' not found
}
p++;
q = p;
while (*q != 0 && *q != '+') q++;
//if (*q == 0) return NULL;// '+' not found
while (p <= q) *dst++ = *p++;
dst--;
*dst = 0;
q++;
return q;
}
#define MAX_LEN 100
int main() {
char username[MAX_LEN];
char password[MAX_LEN];
char name[MAX_LEN];
char inputArray[MAX_LEN] = "username=Alex+password=123+real=Alex";
char *p = inputArray;
p = read_str(p, username);
if (p == NULL)return 1; // error
p = read_str(p, password);
if (p == NULL)return 1; // error
read_str(p, name);
printf("username: %s \n", username);
printf("password: %s \n", password);
printf(" name: %s \n", name);
}

C split a char array into different variables

In C how can I separate a char array by a delimiter? Or is it better to manipulate a string? What are some good C char manipulation functions?
#include<string.h>
#include<stdio.h>
int main()
{
char input[16] = "abc,d";
char *p;
p = strtok(input, ",");
if(p)
{
printf("%s\n", p);
}
p = strtok(NULL, ",");
if(p)
printf("%s\n", p);
return 0;
}
you can look this program .First you should use the strtok(input, ",").input is the string you want to spilt.Then you use the strtok(NULL, ","). If the return value is true ,you can print the other group.
Look at strtok(). strtok() is not a re-entrant function.
strtok_r() is the re-entrant version of strtok(). Here's an example program from the manual:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *str1, *str2, *token, *subtoken;
char *saveptr1, *saveptr2;
int j;
if (argc != 4) {
fprintf(stderr, "Usage: %s string delim subdelim\n",argv[0]);
exit(EXIT_FAILURE);
}
for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
token = strtok_r(str1, argv[2], &saveptr1);
if (token == NULL)
break;
printf("%d: %s\n", j, token);
for (str2 = token; ; str2 = NULL) {
subtoken = strtok_r(str2, argv[3], &saveptr2);
if (subtoken == NULL)
break;
printf(" --> %s\n", subtoken);
}
}
exit(EXIT_SUCCESS);
}
Sample run which operates on subtokens which was obtained from the previous token based on a different delimiter:
$ ./a.out hello:word:bye=abc:def:ghi = :
1: hello:word:bye
--> hello
--> word
--> bye
2: abc:def:ghi
--> abc
--> def
--> ghi
One option is strtok
example:
char name[20];
//pretend name is set to the value "My name"
You want to split it at the space between the two words
split=strtok(name," ");
while(split != NULL)
{
word=split;
split=strtok(NULL," ");
}
You could simply replace the separator characters by NULL characters, and store the address after the newly created NULL character in a new char* pointer:
char* input = "asdf|qwer"
char* parts[10];
int partcount = 0;
parts[partcount++] = input;
char* ptr = input;
while(*ptr) { //check if the string is over
if(*ptr == '|') {
*ptr = 0;
parts[partcount++] = ptr + 1;
}
ptr++;
}
Note that this code will of course not work if the input string contains more than 9 separator characters.
I came up with this.This seems to work best for me.It converts a string of number and splits it into array of integer:
void splitInput(int arr[], int sizeArr, char num[])
{
for(int i = 0; i < sizeArr; i++)
// We are subtracting 48 because the numbers in ASCII starts at 48.
arr[i] = (int)num[i] - 48;
}
This is how I do it.
void SplitBufferToArray(char *buffer, char * delim, char ** Output) {
int partcount = 0;
Output[partcount++] = buffer;
char* ptr = buffer;
while (ptr != 0) { //check if the string is over
ptr = strstr(ptr, delim);
if (ptr != NULL) {
*ptr = 0;
Output[partcount++] = ptr + strlen(delim);
ptr = ptr + strlen(delim);
}
}
Output[partcount++] = NULL;
}
In addition, you can use sscanf for some very simple scenarios, for example when you know exactly how many parts the string has and what it consists of. You can also parse the arguments on the fly. Do not use it for user inputs because the function will not report conversion errors.
Example:
char text[] = "1:22:300:4444:-5";
int i1, i2, i3, i4, i5;
sscanf(text, "%d:%d:%d:%d:%d", &i1, &i2, &i3, &i4, &i5);
printf("%d, %d, %d, %d, %d", i1, i2, i3, i4, i5);
Output:
1, 22, 300, 4444, -5
For anything more advanced, strtok() and strtok_r() are your best options, as mentioned in other answers.

Resources