i have built a small c program which i am trying to set a structure value
**static faut fautData**
typedef struct
{
char ds[25];
char ec[51];
char vc[51];
char rc[51];
char rb[2];
char eb[2];
char vb[2];
char es[10];
char dias[50];
char ss[10];
} faut;
i have a function name update to set values for the above specified structure
but when i try to set ** faut.es ** # the beginning of the update function the value does not get assigned(in my print call it does not get reflect.
when i set the same value # the end i i am able to print the output and see the value
why is that??
sample code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char ds[25];
char ec[51];
char vc[51];
char rc[51];
char rb[2];
char eb[2];
char vb[2];
char es[10];
char dias[50];
char ss[10];
} faut;
typedef struct
{
unsigned int d5;
unsigned int d10;
unsigned int d20;
unsigned int d50;
unsigned int d100;
unsigned int d500;
unsigned int d1000;
unsigned int an;
unsigned int rn;
unsigned int cn;
int alr;
}ncd;
static ncd chkncd;
int cdc;
void admin_init(void)
{
char Keys[17];
int i = 0;
int keysEnabled;
int shift = 0x01;
keysEnabled=0xFF;
strcpy(Keys,"0000000000000000");
//keysEnabled = getKeysToEnable();
for(i=0;i<8;i++)
{
switch((keysEnabled & shift))
{
case 0x10:
Keys[0]=0x34;
Keys[1]=0x36;
break;
case 0x20:
Keys[2]=0x34;
Keys[3]=0x37;
break;
case 0x40:
Keys[4]=0x34;
Keys[5]=0x38;
break;
case 0x80:
Keys[6]=0x34;
Keys[7]=0x39;
break;
case 0x08:
Keys[8]=0x34;
Keys[9]=0x34;
break;
case 0x04:
Keys[10]=0x34;
Keys[11]=0x33;
break;
case 0x02:
Keys[12]=0x34;
Keys[13]=0x32;
break;
case 0x01:
Keys[14]=0x34;
Keys[15]=0x31;
break;
default:
break;
}
shift = shift << 1;
}
printf("%s",Keys);
}
void update(void)
{
char temp[512];
int i = 0;
static faut fautData;
memset(&fautData, '\0', sizeof(fautData));
int cat =0;
if(cat) // Any failure
{
strncpy(fautData.ds, "3", 1);
strncpy(fautData.es, "4", 1);
memset(temp,'\0',sizeof(temp));
}
else
{
strncpy(fautData.es, "2",1);
strncpy(fautData.ds, "0",2);
}
strcpy(&fautData.ec[0],"00000000000000000000000000000000000000000000000000");//00000000000000000000000000000000000000000000000000
strcpy(&fautData.rc[0],"00000000000000000000000000000000000000000000000000");//00000000000000000000000000000000000000000000000000
strcpy(fautData.vc,"");
if(chkncd.d50 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"01");
sprintf(temp, "%03d", chkncd.d50);
strcat(fautData.vc,temp);
}
if(chkncd.d100 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"02");
sprintf(temp, "%03d", chkncd.d100);
strcat(fautData.vc,temp);
}
if(chkncd.d500 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"03");
sprintf(temp, "%03d", chkncd.d500);
strcat(fautData.vc,temp);
}
if(chkncd.d1000 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"04");
sprintf(temp, "%03d", chkncd.d1000);
strcat(fautData.vc,temp);
}
sprintf(fautData.vb, "%02d", chkncd.an);
fautData.rb[0] = 0x30;
fautData.rb[1] = 0x30;
fautData.eb[0] = 0x30;
fautData.eb[1] = 0x30;
strncpy(fautData.dias, "0", 1);
cdc = cdc - chkncd.an - chkncd.cn;
if ((chkncd.alr) || (cdc < 2450))
strncpy(fautData.ss, "4", 1);
else
strncpy(fautData.ss, "1", 1);
sprintf(temp,"keysEnabled:\nds : %s\nec : %s\n vc : %s\nrc : %s\n rb : %s\n eb : %s\n vb : %s\n es : %s\n ss : %s\n", fautData.ds, fautData.ec, fautData.vc, fautData.rc, fautData.rb, fautData.eb, fautData.vb, fautData.es, fautData.dias, fautData.ss);
printf("%s",temp);
}
int main(void) {
cdc=2300;
chkncd.d5=0;
chkncd.d10=0;
chkncd.d20=0;
chkncd.d50=0;
chkncd.d100=0;
chkncd.d500=1;
chkncd.d1000=0;
chkncd.alr=0;
chkncd.an=1;
chkncd.rn=0;
chkncd.cn=0;
update();
return EXIT_SUCCESS;
}
Your problem is here:
sprintf(fautData.vb, "%02d", chkncd.an);
fautData.vb is two bytes, but your sprintf call will write three bytes: the two-digit number followed by a null terminator, which overflows the vb array and overwrites fautData.es.
When you do
strncpy(fautData.es, "2",1);
you are copying "at most 1 character". This leaves you without the terminating null, and that can cause a problem. As the description says:
No null-character is implicitly appended at the end of destination if
source is longer than num. Thus, in this case, destination shall not
be considered a null terminated C string (reading it as such would
overflow).
You need to do
strncpy(fautData.es, "2",2);
to make sure you have a valid string.
Further, in your line
sprintf(fautData.vb, "%02d", chkncd.an);
You are putting a '\0' after .vb (so really you are writing three characters in total). But since vb only has space for two characters, the nul will be put as the first element of the next structure element - which happens to be .es. Thus, when you try to print .es, the first character is "end of string", and nothing gets printed.
If you change the struct to have three elements of space for vb:
char vb[3];
the problem goes away.
This is a tricky thing that happens all the time; you need one more space for each string than you have "characters". That '\0' takes space...
update as you said that you are constrained to have two bytes, you have to limit yourself to printing just two characters to the structure element during writing - and you have to limit yourself to printing only two characters during printing. Example:
void set_vb(int value) {
char temp[3];
sprintf(temp, "%02d", value);
memcpy(fautData.vb, temp, 2);
}
void print_vb(void {
printf("%.2s", fautData.vb);
}
Now you can forget "how to do it right", and just call these two functions when you need to set or print the value of vb. You could do the same for other elements where you run into this issue (given the tight size of your struct, that could apply to many of them...)
Related
This question already has answers here:
Can I initialize string after declaration?
(3 answers)
Closed 2 years ago.
In this code I tried to initialize and pass three strings to a function: action_type; system_type; room
(COLD, HOT, and EMP mean respectivly cooling system, hotting system and employee room).
The code code runs but it doesn't printf the strings. What can I do in order to visualize the strings?
Thanks all.
enter code here
#include <stdio.h>
#include <string.h>
#define T_MAX_EMP 25
#define T_MIN_EMP 15
#define ON 1
#define OFF 0
void SystemAction(char* action_type, char* system_type, char* room, bool power)
{
if(power == OFF)
{
printf ("%s %s %s \n", action_type, system_type, room);
power = ON;
}
else
{
if(power == ON)
{
printf("%s is still on \n", system_type);
}
}
}
void SystemCheck(int n, int system)
{
if(n == 1)
{
printf ("The heating / cooling system works correctly \n");
}
else
{
if(n == 0)
{
printf("System malfunctions have been reported \n");
system = n;
}
else
{
printf ("\n Value entered is incorrect \n");
}
}
}
int main()
{
int n;
int system = 1;
int ch;
int power = OFF;
char c;
char action_type[10];
char system_type[10];
char room[10];
do
{
printf("Enter the character and the integer: \n");
scanf (" %c %d" , &c, &n);
switch(c)
{
case 'e' :
if(system == 0)
{
printf("The system doesn't work \n");
}
else
{
if (n > T_MAX_EMP)
{
action_type[10] = "ON";
system_type[10] = "COLD";
room[10] = "EMP";
SystemAction(action_type, system_type, room, power);
}
else
{
if(n < T_MIN_EMP)
{
action_type[10] = "ON";
system_type[10] = "HOT";
room[10] = "EMP";
SystemAction(action_type, system_type, room, power);
}
}
break;
}
case 's' :
SystemCheck(n, system);
break;
}
printf("Continue? \n");
scanf(" %d", &ch);
}while(ch == 1);
return 0;
}
action_type[10] = "ON"; is not the proper way to assign strings.
You didn't get that code from any reference, book, training material.
Did you make up an entirely new syntax hoping it would work?
Look into strcpy
Arrays do not have the assignment operator.
In statements like these
action_type[10] = "ON";
system_type[10] = "COLD";
room[10] = "EMP";
it seems you want to assign arrays with string literals. However actually you are trying to assign non-existent elements of the arrays with pointers to first characters of the string literals.
What you need is to copy the string literals into arrays like
strcpy( action_type, "ON" );
strcpy( system_type, "COLD" );
strcpy( room, "EMP" );
If You are not going to change elements of the arrays then instead of arrays of characters you could use just pointers like
char *action_type;
char *system_type;
char *room;
In this case the statements like these
action_type = "ON";
system_type = "COLD";
room = "EMP";
will be correct.
Or even to declare the pointers with the qualifier const
const char *action_type;
const char *system_type;
const char *room;
In this case you will need also to change the function declaration
void SystemAction(char* action_type, char* system_type, char* room, bool power);
to the following declaration
void SystemAction( const char* action_type, const char* system_type, const char* room, bool power);
Firstly, your code have to #include <stdbool.h> for bool type.
Secondly, You should use strcpy for copying string to string in c.
strcpy(action_type,"ON");
strcpy(system_type,"COLD");
strcpy(room,"EMP");
and
strcpy(action_type,"ON");
strcpy(system_type,"HOT");
strcpy(room,"EMP");
When you use action_type[10] for example, this is 11th character of array action_type. "ON" is string not character. If you want to assign with character, use ' instead of ". For example
action_type[0] = 'O';
action_type[1] = 'N';
action_type[3] = '\0';
One more thing, action_type[10] is out of the array because the maximum index of action_type is 9 (from 0 to 9).
Here is the problem we have to check if two strings contain the same characters, regardless of order. For example s1=akash s2=ashka match.
My program is showing NO for every input strings;
s1 and s2 are two input strings
t is the number of testcases
->it would be really helpful if you can tell me where is the error I am a beginner
#include<stdio.h>
#include<string.h>
int main(){
int t,i,j;
scanf("%d",&t);
while(t>0){
char s1[100],s2[100];
scanf("%s ",s1);
scanf("%s",s2);
int count=0;
int found[100];
for(i=0;i<strlen(s1)-1;i++){
for(j=0;j<strlen(s1);j++){
if(s1[i]==s2[j]){
found[i]=1;
break;
}
}
}
for(i=0;i<strlen(s1);i++){
if(found[i]!=1){
count=1;
break;
}
}
if(count==1)
printf("NO");
else
printf("YES");
t--;
}
}
Some good answers above suggest sorting the strings first.
If you want to modify your program above to do this job then you need to modify it as you realised. I have a suggestion (in words) for how to do this below - after that there is a modified code that works, and finally a couple of extra points.
I guess that two strings aa and a would not be equal according to your definition, but your program would say that they were equal because once you find a character you do not have anyway of saying that it has been 'used up'
I would suggest that you change your found[] array so that it records when a character in the second string is matched.
I suggest logic as follows.
Loop through all S1 characters
| Loop through S2 charaters
| - if you get a match mark the S2 character as found
| - if you don't get a match by the end of the S2 loops then you are done - they are not equal
At the end of the S1 loop if you have not finished early then every character is matched, but you need to go through found[] array to check that every character in S2 was found.
working code is below....
note
you did not initialize found - it is initialize below in code
the first loop needs to have < strlen(s1) not < strlen(s1)-1
the second loop you should have been going to strlen(s2).
logic changed as described above so that found records characters found in s2 not s1
logic also changed so that if a character in s1 is not found the loop breaks early. There are tests to see if the loop broke early to see if the values of i and j are what we expect at the end of the loop.
edited code below (at the bottom below the code are some extra comments)
#include<stdio.h>
#include<string.h>
int main(){
int t,i,j;
scanf("%d",&t);
while(t>0){
char s1[100],s2[100];
scanf("%s ",s1);
scanf("%s",s2);
int count=0;
int found[100]={ 0 };
for(i=0;i<strlen(s1);i++){
for(j=0;j<strlen(s2);j++){
if(found[j]==1) continue; // character S2[j] already found
if(s1[i]==s2[j]){
found[j]=1;
break;
}
}
if (j==strlen(s2)) {
break; // we get here if we did not find a match for S1[i]
}
}
if (i!=strlen(s1)) {
printf("NO"); // we get here if we did not find a match for S1[i]
}
else {
// matched all of S1 now check S2 all matched
for(i=0;i<strlen(s2);i++){
if(found[i]!=1){
count=1;
break;
}
}
if(count==1) {
printf("NO");
}
else {
printf("YES");
}
}
t--;
}
return 0;
}
Two extra points to make your code more efficient.
First, as suggested by #chux it will probably be faster not to have strlen(s2) in the condition for the loop. What you could have instead would be for (j=0;s2[j];j++). This works because the final character at the end of the string will have the value 0 and in C a value of 0 means false.. in the for loop the loop runs whilst the logic statement is true and when it is false the loop stops. The speed up of not using strlen[s2] in the loop is because the compiler might decide to calculate strlen[s2] each time you go through the loop, which means counting for l2 if l2 is the length of s2 - thus as you have to go through the two loops l1*l2 times potentially with the strlen counting you actually have l1*l2*l2 steps.
secondly, you could speed up many tests by checking to see if the lengths of the two strings are different before checking if they contain the same number of the same types of character.
As suggested in my comment, and since it's now a bit more clear, an easy way to compare two multisets represented as strings is to:
Sort the two strings (easy using the qsort() standard function)
Compare the result (using the strcmp() standard function)
This will work since it will map both "akash" and "ashka" to "aahks", before comparing.
Sort both the strings by using bubble sort or any other tech. you know , then simply compair both strings by using strcmp() function .
for(i=0;i<strlen(s1)-1;i++){
for(j=0;j<strlen(s1);j++){
if(s1[i]==s2[j]){
found[i]=1;
break;
}
}
}
I am not able to understand why are you using j<strlen(s1) is second loop.
I think simple solution will be sorting the characters alphabetically and comparing one by one in single loop.
First, note that found is never initialized. The values within it are unknown. It ought to be initialized by setting every element to zero before each test for equality. (Or, if not every element, every element up to strlen(s1)-1, as those are the ones that will be used.)
Once found is initialized, though, there is another problem.
The first loop on i uses for(i=0;i<strlen(s1)-1;i++). Within this, found[i] is set if a match is found to s1[i]. Note that i never reaches strlen(s1)-1 within the loop, since the loop terminates when it does.
The second loop on i uses for(i=0;i<strlen(s1);i++). Within this loop, found[i] is tested to see if it is set. Note that i does reach strlen(s1)-1, since the loop terminates only when i reaches strlen(s1). However, found[strlen(s1)-1] can never have been set by the first loop, since i never reaches strlen(s1)-1 in the first loop. Therefore, the second loop would always report failure.
Additionally, it is not clear whether two strings ought to be considered equal if and only if they are anagrams (the characters in one can be rearranged to form the other string, without adding or removing any characters) or if each character in one string is found at least once in the other (“aaabbc” would be equal to “abbccc”, because both strings contain a, b, and c).
As written, with the initialization and loop bugs fixed, your program tests whether each character in the first string appears in the second string. This is not an equivalence relation because it is not reflexive: It does not test whether each character in the second string appears in the first string. So, you need to think more about what property you want to test and how to test for it.
Complicated solutions I did as a training. Two implementations controlled with a macro below.
First implementation loops through every character in the string, counts it's count in the first and second string and compares the values.
The second implementation allocates and creates a map of characters with count for each string and then compares these maps.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
// configuration
#define STRCHARSETCNTCMP_METHOD_FOREACH 0
#define STRCHARSETCNTCMP_METHOD_MAP 1
// eof configuration
//#define dbgln(fmt, ...) fprintf(stderr, "%s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
#define dbgln(...) ((void)0)
/**
* STRing CHARacter SET CouNT CoMPare
* compare the count of set of characters in strings
* #param first string
* #param the other string
* #ret true if each character in s1 is used as many times in s2
*/
bool strcharsetcntcmp(const char s1[], const char s2[]);
// Count how many times the character is in the string
size_t strcharsetcntcmp_count(const char s[], char c)
{
assert(s != NULL);
size_t ret = 0;
while (*s != '\0') {
if (*s == c) {
++ret;
}
*s++;
}
return ret;
}
// foreach method implementation
bool strcharsetcntcmp_method_foreach(const char s1[], const char s2[])
{
const size_t s1len = strlen(s1);
const size_t s2len = strlen(s2);
if (s1len != s2len) {
return false;
}
for (size_t i = 0; i < s1len; ++i) {
const char c = s1[i];
const size_t cnt1 = strcharsetcntcmp_count(s1, c);
const size_t cnt2 = strcharsetcntcmp_count(s2, c);
// printf("'%s','%s' -> '%c' -> %zu %zu\n", s1, s2, c, cnt1, cnt2);
if (cnt1 != cnt2) {
return false;
}
}
return true;
}
// array of map elements
struct strcharsetcntcmp_map_s {
size_t cnt;
struct strcharsetcntcmp_map_cnt_s {
char c;
size_t cnt;
} *map;
};
// initialize empty map
void strcharsetcntcmp_map_init(struct strcharsetcntcmp_map_s *t)
{
assert(t != NULL);
dbgln("%p", t);
t->map = 0;
t->cnt = 0;
}
// free map memory
void strcharsetcntcmp_map_fini(struct strcharsetcntcmp_map_s *t)
{
assert(t != NULL);
dbgln("%p %p", t, t->map);
free(t->map);
t->map = 0;
t->cnt = 0;
}
// get the map element for character from map
struct strcharsetcntcmp_map_cnt_s *strcharsetcntcmp_map_get(const struct strcharsetcntcmp_map_s *t, char c)
{
assert(t != NULL);
for (size_t i = 0; i < t->cnt; ++i) {
if (t->map[i].c == c) {
return &t->map[i];
}
}
return NULL;
}
// check if the count for character c was already added into the map
bool strcharsetcntcmp_map_exists(const struct strcharsetcntcmp_map_s *t, char c)
{
return strcharsetcntcmp_map_get(t, c) != NULL;
}
// map element into map, without checking if it exists (only assertion)
int strcharsetcntcmp_map_add(struct strcharsetcntcmp_map_s *t, char c, size_t cnt)
{
assert(t != NULL);
assert(strcharsetcntcmp_map_exists(t, c) == false);
dbgln("%p %p %zu %c %zu", t, t->map, t->cnt, c, cnt);
void *pnt = realloc(t->map, sizeof(t->map[0]) * (t->cnt + 1));
if (pnt == NULL) {
return -errno;
}
t->map = pnt;
t->map[t->cnt].c = c;
t->map[t->cnt].cnt = cnt;
t->cnt++;
return 0;
}
// create map from string, map needs to be initialized by init and needs to be freed with fini
int strcharsetcntcmp_map_parsestring(struct strcharsetcntcmp_map_s *t, const char s[])
{
assert(t != NULL);
assert(s != NULL);
int ret = 0;
while (*s != '\0') {
const char c = *s;
if (!strcharsetcntcmp_map_exists(t, c)) {
const size_t cnt = strcharsetcntcmp_count(s, c);
ret = strcharsetcntcmp_map_add(t, c, cnt);
if (ret != 0) {
break;
}
}
++s;
}
return ret;
}
// compare two maps if they have same sets of characters and counts
bool strcharsetcntcmp_cmp(const struct strcharsetcntcmp_map_s *t, const struct strcharsetcntcmp_map_s *o)
{
assert(t != NULL);
assert(o != NULL);
if (t->cnt != o->cnt) {
return false;
}
for (size_t i = 0; i < t->cnt; ++i) {
const char c = t->map[i].c;
const size_t t_cnt = t->map[i].cnt;
struct strcharsetcntcmp_map_cnt_s *o_map_cnt = strcharsetcntcmp_map_get(o, c);
if (o_map_cnt == NULL) {
dbgln("%p(%zu) %p(%zu) %c not found", t, t->cnt, o, o->cnt, c);
return false;
}
const size_t o_cnt = o_map_cnt->cnt;
if (t_cnt != o_cnt) {
dbgln("%p(%zu) %p(%zu) %c %zu != %zu", t, t->cnt, o, o->cnt, c, t_cnt, o_cnt);
return false;
}
dbgln("%p(%zu) %p(%zu) %c %zu", t, t->cnt, o, o->cnt, c, t_cnt);
}
return true;
}
// map method implementation
bool strcharsetcntcmp_method_map(const char s1[], const char s2[])
{
struct strcharsetcntcmp_map_s map1;
strcharsetcntcmp_map_init(&map1);
if (strcharsetcntcmp_map_parsestring(&map1, s1) != 0) {
abort(); // <insert good error handler here>
}
struct strcharsetcntcmp_map_s map2;
strcharsetcntcmp_map_init(&map2);
if (strcharsetcntcmp_map_parsestring(&map2, s2) != 0) {
abort(); // <insert good error handler here>
}
const bool ret = strcharsetcntcmp_cmp(&map1, &map2);
strcharsetcntcmp_map_fini(&map1);
strcharsetcntcmp_map_fini(&map2);
return ret;
}
bool strcharsetcntcmp(const char s1[], const char s2[])
{
assert(s1 != NULL);
assert(s2 != NULL);
#if STRCHARSETCNTCMP_METHOD_FOREACH
return strcharsetcntcmp_method_foreach(s1, s2);
#elif STRCHARSETCNTCMP_METHOD_MAP
return strcharsetcntcmp_method_map(s1, s2);
#endif
}
// unittests. Should return 0
int strcharsetcntcmp_unittest(void)
{
struct {
const char *str1;
const char *str2;
bool eq;
} const tests[] = {
{ "", "", true, },
{ "a", "b", false, },
{ "abc", "bca", true, },
{ "aab", "abb", false, },
{ "aabbbc", "cbabab", true, },
{ "123456789012345678901234567890qwertyuiopqwertyuiopasdfghjklasdfghjklzxcvbnmzxcvbnm,./;", "123456789012345678901234567890qwertyuiopqwertyuiopasdfghjklasdfghjklzxcvbnmzxcvbnm,./;", true },
{ "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", true },
{ "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900", false },
};
int ret = 0;
for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) {
const bool is = strcharsetcntcmp(tests[i].str1, tests[i].str2);
if (is != tests[i].eq) {
fprintf(stderr,
"Error: strings '%s' and '%s' returned %d should be %d\n",
tests[i].str1, tests[i].str2, is, tests[i].eq);
ret = -1;
}
}
return ret;
}
int main()
{
return strcharsetcntcmp_unittest();
}
I'm new in C programming. I've written this code from RTKLIB library.
extern void satno2id(int sat, char *id)
{
int prn;
switch (satsys(sat, &prn)) {
case SYS_GPS: sprintf(id,"G%02d",prn-MINPRNGPS+1); return;
case SYS_GLO: sprintf(id,"R%02d",prn-MINPRNGLO+1); return;
case SYS_GAL: sprintf(id,"E%02d",prn-MINPRNGAL+1); return;
case SYS_BDS: sprintf(id,"C%02d",prn-MINPRNBDS+1); return;
}
strcpy(id, "");
}
In this function first argument is Input and second is Output. Now the question is how I get the value of second argument in main() function?
I've written this block of code but it's getting error. What's wrong here?
int main(){
char *id;
satno2id(68, &id);
printf("satellite number is %s", *id);
}
In C, the name of an array degrades to a pointer to the first element of that array.
The id in the function expects a pointer to the first element of a character array (string). This is evident because sprintf() function, which is used to write to a character array is used in satno2id().
So send an char array instead like
char id[4];
satno2id(68, id);
I made the size of the array to be 4 as satno2() seems to be writing a string of length 3. The extra byte is to store the \0 terminator.
You need to pass an array to satno2id, not an uninitialized pointer. Also, to avoid buffer overflow you also need to pass the length of the array so the function can assert that the array is long enough.
#include <assert.h>
#define LEN(array) (sizeof (array) / sizeof (array)[0])
extern void satno2id(int sat, char id[], int idLen)
{
int prn;
assert(idLen >= 4 + 1);
switch (satsys(sat, &prn)) {
case SYS_GPS:
sprintf(id, "G%02d", prn - MINPRNGPS + 1);
break;
case SYS_GLO:
sprintf(id, "R%02d", prn - MINPRNGLO + 1);
break;
case SYS_GAL:
sprintf(id, "E%02d", prn - MINPRNGAL + 1);
break;
case SYS_BDS:
sprintf(id, "C%02d", prn - MINPRNBDS + 1);
break;
default:
strcpy(id, "");
}
}
int main(void)
{
char id[8];
satno2id(68, id, LEN(id));
printf("satellite number is %s\n", id);
return 0;
}
I have 26 values's that i am considering as Special Symbol and are as with special delimeter "$" the value's can be from $A to $Z.
Same time i have a predefined template as:
I have $A,$B,$C.....
Now i am allowing user to input a string that can contain a special symbol and the values of those example:
Input - $ACar $BBike $CTruck.
Then my output should be : *I have Car,Bike,Truck... *
As now all special symbol has been replaced by its values.
Note 1.if $A Car $A Bike is the input value then it should take $A as Car rest should be discarted.
If input string doesn't contain any special symbol the there should be no change in output and output will be
I have $A,$B,$C.....
3.if input start as i am a men $A glass then till $A all values should be discarted.
Which approach should i follow to make this possible?
I am thinking to do strstr on the input string and compare those with my special symbol and store the position of Special Symbol in a list and then as per the position i am thinking to take the values but i don't think it will work for me.
Processing is simplified by using a dynamic string.
like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct dstr {
size_t size;
size_t capacity;
char *str;
} Dstr;//dynamic string
Dstr *dstr_make(void){
Dstr *s;
s = (Dstr*)malloc(sizeof(Dstr));
s->size = 0;
s->capacity=16;
s->str=(char*)realloc(NULL, sizeof(char)*(s->capacity += 16));
return s;
}
void dstr_addchar(Dstr *ds, const char ch){
ds->str[ds->size] = ch;
if(++ds->size == ds->capacity)
ds->str=(char*)realloc(ds->str, sizeof(char)*(ds->capacity += 16));
}
void dstr_addstr(Dstr *ds, const char *s){
while(*s) dstr_addchar(ds, *s++);
//dstr_addchar(ds, '\0');
}
void dstr_free(Dstr *ds){
free(ds->str);
free(ds);
}
void dic_entry(char *dic[26], const char *source){
char *p, *backup, ch;
p = backup = strdup(source);
for(;NULL!=(p=strtok(p, " \t\n"));p=NULL){
if(*p == '$' && isupper(ch=*(p+1))){
if(dic[ch -'A'] == NULL)
dic[ch -'A'] = strdup(p+2);
}
}
free(backup);
}
void dic_clear(char *dic[26]){
int i;
for(i=0;i<26;++i){
if(dic[i]){
free(dic[i]);
dic[i] = NULL;
}
}
}
int main(void){
const char *template = "I have $A,$B,$C.";
char *dic[26] = { 0 };
char buff[1024];
const char *cp;
Dstr *ds = dstr_make();
printf("input special value setting: ");
fgets(buff, sizeof(buff), stdin);
dic_entry(dic, buff);
for(cp=template;*cp;++cp){
if(*cp == '$'){
char ch;
if(isupper(ch=*(cp+1)) && dic[ch - 'A']!=NULL){
dstr_addstr(ds, dic[ch - 'A']);
++cp;
} else {
dstr_addchar(ds, *cp);
}
} else {
dstr_addchar(ds, *cp);
}
}
dstr_addchar(ds, '\0');
printf("result:%s\n", ds->str);
dic_clear(dic);
dstr_free(ds);
return 0;
}
/* DEMO
>a
input special value setting: $ACar $BBike $CTruck
result:I have Car,Bike,Truck.
>a
input special value setting: $BBike
result:I have $A,Bike,$C.
*/
What you're describing is called a Macro Processor or Macro Expander.
You can store your symbol table in an array indexed by the input char.
char *symtab[256] = {0};
Since the symbol names are single-letters, you can use strchr to find the first '$' and check if the next char is a letter (isupper()).
For the actual replacement, it will require some delicate memory management unless you just use really big buffers and make sure to only feed it small data.
If symtab['A'] == "Car" then you can loc = strstr(line, "$A"). Then loc-line is the length of the prefix part, 2 is the length of the symbol name being deleted, strlen("Car") is the length of the replacement, and strlen(loc+2) is the length of the suffix part. So the new string size should be
char *result = malloc( (loc-line) - 2 + strlen(symtab['A']) + strlen(loc+2) + 1);
Then patching up the new string is
strcpy(result,line);
strcpy(result + (loc-line), symtab['A']);
strcpy(result + (loc-line) + strlen(symtab['A']), loc+2);
Notice these are strcpy not strcat which appends strings together. The second and third strcpy calls overwrite the tail of the string just copied.
I've created a binary file with three persons (Code-Name-Sex) when I write the data into the file and then I read them, it work perfectly so..
I want that the next function read all the information of the X person have (if it exist).
Syntax:
#include <stdio.h>
struct alu{
int cod;
char name[30]; //alu[0]="juan" alu[1]="pedro" alu[2]="leo"
int sex;
};
int FSearch(char path[],char X[]) {
char Name[30];
FILE *arc;
arc=fopen(path,"rb");
fseek(arc,sizeof(int),SEEK_SET);
while (fread(Name,sizeof(char[30]),1,arc)) {
/*Here is when the errors happen..
The next sentence tell me that A.name don't have
the name from the second time*/
printf("%s and %s.",X,Name);
if (strcmp(Name,X)==0) return 1;
fseek(arc,2*sizeof(int),SEEK_CUR);
}
fclose(arc);
return 0
}
int main(int argc, char **argv)
{
char path[]="file.bin";
printf("\n%d",FSearch(path,"pedro"));
return 0;
}
The output is the following:
pedro and juan.pedro and .pedro and .
0
That means that is found the first name ('juan') but the second and third isn't (pedro and leo).
What is wrong?
Here's how it was:
fseek(arc,sizeof(int),SEEK_SET);
while (fread(Name,sizeof(char[30]),1,arc)) {
if (strcmp(A.name,X)==0) return 1;
fseek(arc,2*sizeof(int),SEEK_CUR); //--> ERROR
}
Here's how it should be:
fseek(arc,sizeof(int),SEEK_SET);
while (fread(Name,sizeof(char[30]),1,arc)) {
if (strcmp(A.name,X)==0) return 1;
fseek(arc,2*sizeof(int)+sizeof(char[2]),SEEK_CUR); //--> SOLVED
}
The problem was the 2nd argument, the Number of bytes to offset from origin, passed to fseek() call, within the while loop. It was counting two INTs but not the two CHARs (before reaching to the second string). You can see the sizeof(char[30]) after the fread() call, it shows 32 bytes, but 30 bytes are allocated to the string.
Why have to move two more bytes? Because any string have in its end, reserved bytes (for indicating the beginning and end of the string). e.g.:
char a[10]="Example";
If you save this into a binary file, this file will have a size of 12 bytes.
I would print the result of the fread call each time through the loop. I bet after the first object you're hitting EOF on the file. My prediction is that the first fread call returns 1, and the others return 0.
I don't know your binary file format.
Your code tell the binary file have names only with 30 characters.
struct alu{
int cod;
char name[30]; //juan - pedro - leo
int sex;
};
This structure size is not 38 bytes.
Check structure size.
printf("%d", sizeof(struct alu));
structure size depend on your compiler option...
If your binary format has bellow format.
{ // 1st record
cod = 10
names[30] = "juan"
sex = 1
}
{ // 2nd record
cod = 20
names[30] = "pedro"
sex = 1
}
{ // 3rd record
cod = 12
names[30] = "leo"
sex = 2
}
See your code.
#include <stdio.h>
#pragma pack(push, 1) or 4 or 8 depend on your binary format.
struct alu{
int cod;
char name[30]; //juan - pedro - leo
int sex;
};
#pragma pack(pop)
int FSearch(char path[],char X[]) {
char Name[30];
struct alu A;
FILE *arc;
arc=fopen(path,"rb");
//fseek(arc,sizeof(char[30]),SEEK_SET);
fseek(arc,0,SEEK_SET); // first record.
//while (fread(Name,sizeof(char[30]),1,arc)) {
while (fread(A,sizeof(A),1,arc)) {
/*Here is when the errors happen..
The next sentence tell me that A.name don't have
the name from the second time*/
printf("%s and %s.",X,A.name);
if (strcmp(A.name,X)==0) {
printf("Information of %s:\n",X);
//fshow_str(A);
fclose(arc);
return 1; // found
}
}
fclose(arc);
return 0; // not found
}
int main(int argc, char **argv)
{
char path[]="file.bin";
printf("\n%d",FSearch(path,"pedro"));
return 0;
}
cod size depend on compiler OPTION!!!
int FSearch(char path[],char X[]) {
char Name[30];
struct alu A;
FILE *arc;
arc=fopen(path,"rb");
fseek(arc,0,SEEK_SET); // first record.
//while (fread(Name,sizeof(char[30]),1,arc)) {
while (1) {
//if ( -1 == fseek(arc,4,SEEK_CUR)) // Important!!! case structure pack(4) for skip cod or
// break;
if ( -1 == fseek(arc,8,SEEK_CUR)) // Important!!! case structure pack(8) for skip cod
break;
if (!fread(Name,sizeof(Name),1,arc))
break;
A.name = Name;
/*Here is when the errors happen..
The next sentence tell me that A.name don't have
the name from the second time*/
printf("%s and %s.",X,A.name);
if (strcmp(A.name,X)==0) {
printf("Information of %s:\n",X);
//fshow_str(A);
fclose(arc);
return 1; // found
}
}
//if ( -1 == fseek(arc,4,SEEK_CUR)) // Important!!! case structure pack(4) for skip sex or
// break;
if ( -1 == fseek(arc,8,SEEK_CUR)) // Important!!! case structure pack(8) for skip sex
break;
fclose(arc);
return 0; // not found
}
Binary file and structure are alined with 4 bytes.
// Attention! pragma pack(push, 4) needs!!!
// Your now running machine is 32 bits system.
// This source code will invoke addressing fault 64 bits NON Intel processor.
#pragma pack(push, 4) // align 4 bytes.
struct alu{
int cod; // Integer type. 4 bytes on 32bits system. but 8 bytes on 64 bits system.
// I recommend using "long" type. "long" type is 4 bytes on any system.
char name[30]; //juan - pedro - leo
int sex; // also, Integer type.
};
#pragma pack(pop)
int FSearch(char path[],char X[]) {
char Name[30];
struct alu A;
FILE *arc;
arc=fopen(path,"rb");
fseek(arc,0,SEEK_SET); // first record.
//while (fread(Name,sizeof(char[30]),1,arc)) {
while (1) {
if ( -1 == fseek(arc,4,SEEK_CUR)) // Skip "cod" 4 bytes.
break;
if (!fread(Name,sizeof(Name),1,arc)) // Read "name" 30 bytes.
break;
if ( -1 == fseek(arc,2,SEEK_CUR)) // Skip "name"'s aligned 2 bytes.
break;
A.name = Name;
/*Here is when the errors happen..
The next sentence tell me that A.name don't have
the name from the second time*/
printf("%s and %s.",X,A.name);
if (strcmp(A.name,X)==0) {
printf("Information of %s:\n",X);
//fshow_str(A);
fclose(arc);
return 1; // found
}
}
if ( -1 == fseek(arc,4,SEEK_CUR)) // Skip "sex" 4 bytes.
break;
fclose(arc);
return 0; // not found
}
printf in main() printed the return value of FSearch(), if you want to see if the result is found, should at least return a bool value in FSearch()