Is there any manual way to initialize the string in struct ? I used to initialize string in struct using strcpy function such as:
typedef struct {
int id;
char name[20];
int age;
} employee;
int main()
{
employee x;
x.age=25;
strcpy(x.name,"sam");
printf("employee age is %d \n",x.age);
printf("employee name is %s",x.name);
return 0;
}
Strictly speaking this
strcpy(x.name,"sam");
is not an initialization.
if to speak about the initialization then you can do it the following way
employee x = { .name = "sam", .age = 25 };
or
employee x = { .name = { "sam" }, .age = 25 };
This is equivalent to the following initialization
employee x = { 0, "sam", 25 };
or
employee x = { 0, { "sam" }, 25 };
Or you even can use a compound literal of the type employee to initialize the object x though that is not efficient.
Otherwise if is not an initialization but an assignment of the data member of the structure then indeed you have to use at least strcpy or strncpy.
max - including trailing zero
char *mystrncpy(char *dest, const char *src, size_t max)
{
char *tmp = dest;
if (max)
{
while (--max && *src)
{
*dest++ = *src++;
}
*dest++ = '\0';
}
return tmp;
}
You can write your own version of strcpy:
void mycopy(char *dest, const char *source, size_t ndest)
{
assert(ndest != 0);
while (--ndest > 0 && (*dest++ = *source++))
;
}
You're not using strcpy anymore. Plus it is safer.
Related
I am quite new in C, and I am using the json-c library. I am completely sure that the problem I have is with json_object_get_string, because if I don't use it and put a string manually in my structure it works in valgrind without any memory leak.
I put a reduced version to make it clearer.
struct Example {
char *id;
char *name;
char *logPath;
};
struct Examples {
struct Example *examples;
size_t size;
};
struct Examples list() {
size_t i, count = 0;
struct Example *examples = NULL;
for (i = 0; i < 59; i++) {
json_object *root_obj = json_object_from_file("path.json");
json_object *jID;
json_object *jName;
json_object *jLogPath;
if (json_object_object_get_ex(root_obj, "Name", &jName) ==
TRUE &&
json_object_object_get_ex(root_obj, "LogPath", &jLogPath) ==
TRUE &&
json_object_object_get_ex(root_obj, "ID", &jID) == TRUE) {
char *id = strdup(json_object_get_string(jID));
char *name = strdup(json_object_get_string(jName));
char *logPath = strdup(json_object_get_string(jLogPath));
json_object_put(root_obj);
count++;
struct Examples *tmpExamples = realloc(examples, count * sizeof(struct Example));
if (tmpExamples == NULL) {
if (examples) {
free(examples);
}
die("Realloc");
}
struct Example example = { id, name, logPath };
examples = tmpExamples;
examples[i] = container;
}
struct Examples examplesList = { examples, count };
return examplesList;
}
I have tried to free the variables that I have assigned with strdup after adding it to the struct, but then I lose the real value of the string. I don't really understand what happens.
In the end I have not complicated with so much char pointer and the chars of the struct I have put it as char array if I can name it that way
struct Example {
char id[64];
char name[30];
char logPath[165];
};
struct Example example;
strcpy(example.id, json_object_get_string(jID));
strcpy(example.name, json_object_get_string(jName));
strcpy(example.logPath, json_object_get_string(jLogPath));
json_object_put(root_obj);
This is a practice exam question that I am having some difficulty with:
struct bodytp // Is there an error?
{
char *name; // If so, fix the error.
int len;
};
main()
{
struct bodytp person;
keepname(&person , "Waterman");
printf("%s\n", person.name);
}
void keepname(struct bodytp *onept, const char *last)
{
int len;
char *tpt;
for ( len = 0; last[len] != '\0'; )
len++;
char name[len+1];
for ( tpt = name; *tpt++ = *last++; )
;
onept->name = name;
onept->len = len;
}
I have determined that there is an error, as when I run it, I get garbage output from printf. I have also determined that person's name is indeed "Waterman" after the keepname function call. I have tried dereferencing person.name to person -> name, changing the problem from a stack-based question to a heap-based question by eliminating the ampersand operator and malloc-ing the struct, but nothing worked. Can anyone steer me in the right direction? Thank you in advance.
Is there an error?
struct bodytp // Is there an error?
{
char *name; // If so, fix the error.
int len;
};
No there is no error. It is a valid structure definition.
Now errors follow.:)
Function main shall be declared as
int main( void )
Though it is not an error nevertheless it would be better that before the function call there woud be the function prototype
keepname(&person , "Waterman");
The program has undefined behaviour because there is an assignment of a pointer to the structure by the address of a local array that will be destroyed after exiting the function
void keepname(struct bodytp *onept, const char *last)
{
//...
char name[len+1];
//...
onept->name = name;
//...
}
The valid function could be defined like
void keepname(struct bodytp *onept, const char *last)
{
int len = 0;
char *tpt;
while ( last[len] != '\0' ) len++;
char *name = malloc( len + 1 );
for ( tpt = name; *tpt++ = *last++; ) ;
onept->name = name;
onept->len = len;
}
In this case you have to free the alocated memory in main.
Take into account that you coud use standard C functions strlen and strcpy in the function.
You need to allocate the memory for the name in the heap.
void keepname(struct bodytp *onept, const char *last)
{
int len;
char *tpt;
for ( len = 0; last[len] != '\0';len++);
char *name=malloc(len+1);
onept->name = name;
onept->len = len;
for ( ; *name++ = *last++ ; );
}
I have an *input string from a console. That string might look like: show name year xxx.. and I need an output to look like this:
name: Adi
year: 1994 (for example)..
I have been trying to achieve this by using strtok() function, but I also need to compare every tokon with allowed keyywords(name, year...) if that word is not allowed, than the token needs to be skiped(deleted).. for example in this case it would skip show, and xxx.
Another problem is that I need those tokens in a form of an array in order to work with them and with a structs..
There should be no limit to number of words that could be entered in an input..
I hope you understood what I asked.. so, how to make tokens from a string using strtok or something else and make them be arrays or pointers, and how to compare those tokens with another string ( for example constant: #define NAME "name") and of there are some other inputs to skip(delete) them..
I would really appreciate it if you could help me with this.. Thanks..
I would avoid the array. It provides unnecessary overhead. What you're asking for could be accomplished with something like this:
void parseString(char * string) {
char * name = NULL;
char * year = NULL:
char * ptr = strtok(string, " ");
while (ptr != NULL) {
if (stricmp(ptr, "name") == 0) {
ptr = strtok(ptr, " ");
name = ptr;
/* do whatever with name */
} else if (stricmp(ptr, "year") == 0) {
ptr = strtok(ptr, " ");
/* do whatever with year */
year = ptr;
} /* else if ... */
ptr = strtok(ptr, " ");
}
This gives you a fair amount of flexibility. You check all the terms you need, you don't need to worry about how to allocate the array, and you can access values for settings if necessary.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
char *tolowerstr(char *str){
char *p = str;
while((*p++ = tolower(*p)));
return str;
}
int cmp(const void *a, const void *b){
return strcmp(*(const char **)a, *(const char **)b);
}
bool isBanWord(const char *word){
static const char *table[] =
{ "fuck", "show", "xxx" };//sorted
char **ret, *key;
key = tolowerstr(strdup(word));
ret=bsearch(&key, table, sizeof(table)/sizeof(*table), sizeof(*table), cmp);
free(key);
return !!ret;//ret != NULL ? true : false;
}
//Create and return as a dynamic array of pointer to the copy of the word from a string.
//String passed is destroyed.
char **strToWords(char *str, size_t *size){
const char *delimiters = " .";
size_t count=0;
char **array = malloc(strlen(str)*sizeof(char*));//number of words < string length
if(array){
char *token=strtok(str, delimiters);
for(; token ;token=strtok(NULL, delimiters)){
if(!isBanWord(token))//skip ban word
array[count++] = strdup(token);
}
array[count] = NULL;//End mark
array=realloc(array, (count + 1)*sizeof(*array));//include NULL
}
*size = count;
return array;
}
typedef struct words {
char **words;
size_t n; //number of words
} Words;
void clearWords(Words *w){
size_t i;
for(i=0;i < w->n;++i)
free(w->words[i]);
free(w->words);
w->words = NULL;
w->n = 0;
}
void printWords(Words *w){
size_t i=0;
while(i < w->n){
printf("%s", w->words[i++]);
if(w->words[i])
putchar(' ');
}
putchar('\n');
}
int main(){//DEMO
char sentence[] = "show name year xxx.";//input string. Will be destroyed.
Words w;
w.words = strToWords(sentence, &w.n);
printWords(&w);//name year
clearWords(&w);
return 0;
}
I have a data as shown below, it contains the name of person and age respectively, her i have shown just 3 person names and the respective age, i can also have many names with respective age in that string.
I want to parse this string and store the name and corresponding age in a structure, can u please tell me how to parse this name and age. Ex: I want to get Allan 35 and store it in the below structure in name and age field respectively.So and forth for all the names present in that string.
How to parse the string, i tried strstr() but it was of no use for me. Pls can anyone tell how to parse this string.
struct data_base{
char *name;
int age;
};
char data[] = "Name Allan Age 35 Name John Age 50 Name Jim Age 20 ....."
You can use strtok to extract the tokens.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data_base{
char *name;
int age;
};
#define NAME_TAG "Name "
#define AGE_TAG "Age "
char* getName(char **p){
int tag_size = strlen(NAME_TAG);
if(strncmp(*p, NAME_TAG, tag_size)==0){
char *agep = strstr(*p += tag_size, AGE_TAG);
int len = agep - *p -1;//-1: for space before "Age"
char *name = calloc(len + 1, sizeof(char));
strncpy(name, *p, len);
*p = agep;
return name;
}
return NULL;
}
int getAge(char **p){
int tag_size = strlen(AGE_TAG);
if(strncmp(*p, AGE_TAG, tag_size)==0){
int age = (int)strtol(*p += tag_size, p, 10);
if(**p == ' ')
*p += 1;
return age;
}
return -1;
}
struct data_base *parse(char *data, size_t *size){
char *p = data;
struct data_base *dbp=NULL;
*size = 0;
while(*p){
*size += 1;
dbp = realloc(dbp, sizeof(struct data_base)*(*size));
dbp[*size -1].name = getName(&p);//this is treated as format is correct
dbp[*size -1].age = getAge(&p);
}
return dbp;//realloc(dbp, sizeof(struct data_base)*(*size));
}
int main(void){
char data[] = "Name Allan Age 35 Name John Age 50 Name Jim Age 20";
struct data_base *dbp;
size_t i, size;
dbp = parse(data, &size);
//check print
for(i = 0; i < size ;++i){
printf("Name: %s, Age: %d\n", dbp[i].name, dbp[i].age);
}
//deallocate
return 0;
}
You might want to use sscanf. You'll need %s format for person's name and %d for age.
u can use two pointer to get the begin and end of a word,
use pointer p by strstr to get the place of "Name", then forth 5 to get the begin place of the name , then pointer q by strchr with space to get the end of the name, then you can use strncpy of snprintf to get the exactly name
Create function to handle each record, using sscanf().
// Scan string, return >0 if successful, 0 if done, else error code
int JZ_ScanDB(const char *data, int *Index, struct data_base *Dest) {
if (Dest) {
Dest->age = 0; // Form default answer
Dest->name = 0;
}
if (!data || !Index || !Dest) return -1; // Gremlins in your code
if ((*Index < 0) || (*Index > strlen(data))) return -2; // More gremlins
if (data[*Index] == '\0') return 0; // we are done
char Name[1000];
int retval = sscanf(&data[*Index], "Name %s Age %d %n", Name, &Dest->age, Index);
if (retval != 2) {
return -3;
}
Dest->name = strdup(Name);
return 0;
}
void DoIt() {
char data[] = "Name Allan Age 35 Name John Age 50 Name Jim Age 20";
int i = 0;
struct data_base Person;
int ret;
while ((ret = JZ_ScanDB(data, &i, &Person)) > 0) {
// do something with Person, watch for memory management
}
if (ret) {
// deal with unusual reason for stopping
}
}
I'm creating a lookup table in C
When I define this:
typedef struct {
char* action;
char* message;
} lookuptab;
lookuptab tab[] = {
{"aa","bb"},
{"cc","dd"}
};
it compiles without errors but when I do something like this:
typedef struct {
char* action;
char* message[];
} lookuptab;
lookuptab tab[] = {
{"aaa", {"bbbb", "ccc"}},
{"cc", {"dd", "eeeee"}}
};
I get the following error:
error: initialization of flexible
array member in a nested context
error: (near initialization for
‘tab[0].message’)
How can I initialize the tab array in the second example?
Note: I know all the values inside the tab array.
UPDATE: message could be of different size, e.g
typedef struct {
char* action;
char* message[];
} lookuptab;
lookuptab tab[] = {
{"aaa", {"bbbb", "ccc", "dd"}},
{"cc", {"dd", "eeeee"}}
};
Thank you very much.
Best regards,
Victor
You can't use structures containing a flexible array member in an array (of the structure). See C99 standard §6.7.2.1/2:
A structure or union shall not contain a member with incomplete or function type (hence,
a structure shall not contain an instance of itself, but may contain a pointer to an instance
of itself), except that the last member of a structure with more than one named member
may have incomplete array type; such a structure (and any union containing, possibly
recursively, a member that is such a structure) shall not be a member of a structure or an
element of an array.
So, use a char ** instead (and worry about how you know how many entries there are):
typedef struct
{
const char *action;
const char * const *message;
} lookuptab;
static const lookuptab tab[] =
{
{ "aaa", (const char * const []){ "bbbb", "ccc" } },
{ "cc", (const char * const []){ "dd", "eeeee" } }
};
This uses a C99 construct (§6.5.2.5 Compound literals) - beware if you are not using a C99 compiler.
I think you have to specify the array size to use the struct in another array:
typedef struct {
char* action;
char* message[2];
} lookuptab;
You need to specify a size for the message array member in the struct definition:
#define N ... // maximum number of elements in message array
typedef struct
{
char *action;
char *message[N];
} lookuptab;
lookuptab tab[] = {
{"aa", {"bb", "cc"}},
{"dd", {"ee", "ff"}},
...
};
In this case, N must be at least 2.
If you want each instance of the lookuptab struct to have a different number of elements in the message array, then you will have to allocate each message array separately, meaning you won't be able to use a static initializer:
typedef struct
{
char *action;
char **messages;
} lookuptab;
lookuptab *newEntry(const char *action, size_t numMessages, ...)
{
lookuptab *entry = malloc(sizeof *entry);
if (entry)
{
entry->action = malloc(strlen(action) + 1);
if (entry->action)
strcpy(entry->action, action);
if (numMessages > 0)
{
entry->messages = malloc(sizeof *entry->messages * numMessages);
if (entry->messages)
{
size_t i;
va_list ap;
va_start(ap, numMessages);
for (i = 0; i < numMessages; i++)
{
char *nextMessage = va_arg(ap, char *);
entry->messages[i] = malloc(strlen(nextMessage) + 1);
if (entry->messages[i])
strcpy(entry->messages[i], nextMessage);
}
}
}
}
return entry;
}
int main(void)
{
lookuptab *tab[ENTRIES]; // for some number of ENTRIES
tab[0] = newEntry("AA", 2, "BB", "CC");
tab[1] = newEntry("DD", 3, "EE", "FF", "GG");
tab[2] = newEntry("HH", 0);
...
}
Instead of passing the number of messages explicitly, you can use a sentinel:
tab[0] = newEntry("AA", "BB", "CC", NULL);
but you'll either have to cycle through all the arguments twice (first to get the number to allocate the messages array, then to copy each message) or you'll have to realloc() your array for each message, such as:
size_t numMessages = 0;
...
char *nextMessage
while ((nextMessage = va_arg(ap, char *)) != NULL)
{
char **tmp = realloc(entry->messages, sizeof *entry->messages, numMessages+1);
if (tmp)
{
entry->messages = tmp;
entry->messages[numMessages] = malloc(strlen(nextMessage) + 1);
strcpy(entry->messages[numMessages], nextMessage);
numMessages++;
}
}
typedef struct {
char* action;
char* message[];
} lookuptab;
lookuptab is an incomplete type. You cannot create objects of that type. Either provide a definite size for the message array
typedef struct {
char* action;
char* message[42];
} lookuptab_definite_size;
or use pointers all around and manage memory "by hand"
typedef struct {
char* action;
char** message;
} lookuptab_pointers_all_around;
you can use the flexible array member (all elements will have the same size), but it's a lot of work :-)
#include <stdlib.h>
typedef struct {
char* action;
char* message[];
} lookuptab;
int main(void) {
lookuptab *tab;
tab = malloc(sizeof *tab + 42 * sizeof *tab->message);
/* tab = malloc(elems * (sizeof *tab + 42 * sizeof *tab->message)); */
/* tab[0] ... tab[elems-1] all have the same size */
if (tab) {
tab->action = NULL;
tab->message[0] = NULL;
tab->message[1] = NULL;
/* ... */
tab->message[41] = NULL;
free(tab);
}
return 0;
}