Pointer and Functions - c

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;
}

Related

Initializing a string and passing it to a function [duplicate]

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).

wrong output, can't understand why C

I am a beginner in C programming and I built a function that recieves the string "HodHasharon,frozenYogurt,100". The function cuts the string into 3 pieces where every piece is a field of my City struct.
I want to put "HodHasharon" into
City pcity.name (name of the city), "frozenYogurt" into pcity.popularFood (popular food) and number of residents (100) into pcity.residents.
When i am debugging the output in my function the output is correct but when i print from the main.c I got a concatenated string.
For example, when I print pcity.name I get "HodHashafrozenYod" instead of "HodHasharon" but if I do printf at my function printf->name I get the correct output of "HodHasharon"
What am I doing wrong?
struct of City:
typedef struct City
{
char *name;
char * popluarFood;
int numberOfPeople;
} City;
the function:
City * cutCityData (char *singleLine)
{
City* pcity=(City*)malloc(sizeof(City));
int firstIndex=1;
int endIndex=1;
int checkItarion=0;
while(endIndex<strlen(singleLine))
{//while
while (singleLine[endIndex] != ',')
{//while2
endIndex++;
}//while2
checkItarion++;
char cityDetails[endIndex - firstIndex +1];
memcpy(cityDetails,&singleLine[firstIndex], endIndex);
cityDetails[endIndex - firstIndex] = '\0';
if (checkItarion == 1) {
pcity->name = (char *) malloc(cityDetails);
strcpy(&(pcity->name), cityDetails);
endIndex++;
firstIndex = endIndex;
}
if (checkItarion == 2) {
pcity->popluarFood = (char *) malloc(cityDetails);
strcpy(&(pcity->popluarFood), cityDetails);
endIndex++;
firstIndex=endIndex;
break;
}
}//while
char cityDetails[strlen(singleLine) - firstIndex + 1];
memcpy(cityDetails, &singleLine[firstIndex], sizeof(singleLine-1));
int resdints=atoi(cityDetails);
pcity->numberOfPeople=resdints;
return pcity;
}
from main:
City* pCity=cutCityData(singLine);
printf("%s\n", &(pCity->name));
&(pcity->name) is the address of the pointer variable. You want to copy the string to the memory that it points to, not copy over the pointer. So change:
strcpy(&(pcity->name), cityDetails);
to
strcpy(pcity->name, cityDetails);
You're also giving the wrong argument to malloc(). cityDetails is an array, but the argument should be the number of bytes you want to allocate. So change
pcity->name = (char *) malloc(cityDetails);
to:
pcity->name = malloc(strlen(cityDetails) + 1);
These changes also need to be made for the code that fills in pcity->popularFood as well.
This is wrong:
memcpy(cityDetails, &singleLine[firstIndex], sizeof(singleLine-1));
singleLine is a pointer, so sizeof(singleLine-1) is the number of bytes in a pointer, not the length of the string. This should be:
memcpy(cityDetails, &singleLine[firstIndex], endIndex + 1);

C - Understanding structure's value setting pattern

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...)

How to return a character string to another function?

I am wrting a function which pads a few characters on either right or left depending on the user's choice. I used strcat function to concat the characters to the string and it worked fine in case of right padding, but while left padding I got junk characters so I wrote my own concat function. Still the same result please see the code below.
char *concat(char a[], char b[])
{
int len1=0, len2=0, i, j;
char tmp[100], *tmp2;
trace("concat(): Begin");
len1 = strlen(a);
len2 = strlen(b);
for(i=0, j=0; i<(len1+len2); i++)
{
if(i<len1)
tmp[i]=a[i];
else
tmp[i]=b[j++];
}
tmp[i]='\0';
tmp2 = tmp;
sprintf(str, "Concatenated String: %s", tmp2);
trace(str);
trace("concat(): End");
return tmp2;
}
char *pad(char *field_name, char *field_val)
{
char *temp_var=field_val, *temp_var2;
int i=0;
char pad_var[100];
trace("pad(): Begin");
sprintf(str, "field name to search for: %s and field value to be formatted: %s", field_name, field_val);
trace(str);
get_format_vars(field_name);
sprintf(str, "strlen(field_val) = %d and len = %d", strlen(field_val), len);
trace(str);
if(strlen(field_val)<len)
{
trace("Data should be Padded");
trace(field_val);
for(i=0; i<len-strlen(field_val); i++)
{
pad_var[i] = pc;
}
pad_var[i]='\0';
sprintf(str, "pad_var = %s", pad_var);
trace(str);
switch(pd)
{
case 'l':
case 'L':
sprintf(str, "length of field: ", strlen(field_val));
temp_var = concat(pad_var, field_val);
sprintf(str, "Value after left padding: (%.*s)", len, temp_var);
trace(str);
break;
case 'r':
case 'R':
strcat(field_val, pad_var);
temp_var = field_val;
sprintf(str, "Value after right padding: (%s)", temp_var);
trace(str);
break;
case 'n':
case 'N':
trace("No formatting to be done for this field");
break;
default:
trace("Wrong value for padding type.");
}
trace("Data Padded");
}
else
{
trace("Field length already equal to format length");
}
temp_var2 = temp_var;
sprintf(str, "Data after/without formatting: (%s)", temp_var2);
trace(str);
trace("pad(): End");
return temp_var;
}
Please note, the above program works completely fine in case of right padding.
Please let me know what is it that I am doing wrong due to which when I do left padding, it displays junk characters at the end.
Note: The functions and variable whose reference is not there in the program are declared globally in my program like the function "trace" and the variable "pd".
trace() function takes a string parameter and writes that string to a file.
You should not write your own version of strcat.
You should not return an automatic (local) array - it's out of scope after the function returns, using it invokes undefined behavior.
Either malloc()ate some memory and return that dynamically allocated chunk or memory, or call the functions with an input/output argument, which is an array declared in the caller (as opposed to the callee).
You're returning a pointer to a temporary stack variable that goes out of scope when the function exits. Its memory may (will) then be reused by other function calls. The easiest fix would be to allocate memory dynamically in concat then free it in the caller.
char* tmp = malloc(len1+len2+1);
You could also simplify your concat function to
char* tmp = malloc(len1+len2+1);
strcpy(tmp, a);
strcat(tmp, b);
return tmp;
You allocate result you return on the stack inside the returning function:
char tmp[100]
This may even actually work (contents of the usual, "classic" stack are not broken by return), but only as long as you use or copy the returned string immediately somewhere else without making another call. As soon as you make the second call (system call including), stack is reused and you get garbage.
Assigning the reference to another variable before return has no effect.
Use one of the strdup family functions to return a cloned copy (do not forget to free when no longer needed).

C programming pointers and char array problems

I want to pass the contents of an array to another method and have that method print out the entire array - how would i do this?
Currently:
I'm returning an array from a function.
char* search_value(struct PDB *llist)
{
int realID = -7;
int x = 0;
int task = 0;
char *received;
char theMessage[100];
theMessage[0] = '\0';
printf("Your choice: `Search'\n");
printf("Enter the value you want to find: ");
scanf("%d", &task);
while(llist->data1 != NULL)
{
if(task == llist->taskID)
{
realID = llist->taskID;
strcpy(theMessage, llist->data1);
break;
}
}
return theMessage;
}
i'm getting the return value:
void getMessage(const int GET_MESSAGE)
{
char * received = NULL;
int x = 0;
received = search_value(llist);
printf("%s", received);
}
I want to somehow print the entire value (rather than just the first value to which the pointer is pointing at - how would i do this?
A few corrections and it should work:
// - struct contents shouldn't be changed by the function, make its pointer const.
// - pass a pointer to an allocated array as parameter
char* search_value(const struct PDB *llist, char* theMessage)
{
int realID = -7;
int x = 0;
int task = 0;
char *received;
theMessage[0] = '\0';
printf("Your choice: `Search'\n");
printf("Enter the value you want to find: ");
scanf("%d", &task);
while(llist->data1 != NULL)
{
if(task == llist->taskID)
{
realID = llist->taskID;
strcpy(theMessage, llist->data1);
break;
}
}
return theMessage;
}
void getMessage(const int GET_MESSAGE)
{
char received[100]; // allocate the array outside the function
int x = 0;
search_value(llist, received); // pass a pointer to the first element
printf("%s", received);
}
You have an issue with variable scope here: theMessage is local to the function search_value, so you're returning a pointer to an array which no longer exists once the function completes.
Instead you should use malloc() to allocate the space for theMessage and then subsequently free() it later on outside of the function when you're finished with it —  however this can often lead to memory leaks if you're not diligent about cleaning up after yourself.
You can allocate the memory like so:
char * message = malloc(100);
One alternative would be to allocate the buffer in getMessage() and pass a pointer to the buffer into search_value which could then write into it:
void getMessage(const int GET_MESSAGE)
{
char received[100];
int x = 0;
search_value(llist, received);
printf("%s", received);
}
void search_value(struct PDB *llist, char * buffer)
{
// write to buffer
}
Another option is to declare a char * pointer inside getMessage(), pass a pointer to a pointer into search_value() and again use malloc() to allocate space for the buffer.
Finally, this is a minor style criticism, but you'd do well to learn to stick to one convention for naming your functions, search_value and getMessage are not consistent names, and this will irk many a coder that you work with.
You have several problems with your code. I'm guessing that you want to search a list for some value, then return that value.
The first problem is that you do not actually iterate over the list, but only check the same item over and over again. The other problem is that you return a pointer to a local variable. This is undefined behavior, because as soon as the function returns the memory the pointer points to can be used for something else.
I suggest you change your code as follows:
char *search_value(struct PDB *llist, char *theMessage, size_t theMessageMaxLength)
{
int realID = -7;
int task = 0;
printf("Your choice: `Search'\n");
printf("Enter the value you want to find: ");
scanf("%d", &task);
while(llist != NULL && llist->data1 != NULL)
{
if(task == llist->taskID)
{
realID = llist->taskID;
strncpy(theMessage, llist->data1, theMessageMaxLength);
theMessage[theMessageMaxLength] = '\0';
break;
}
llist = llist->next; /* Assuming the field is named "next" */
}
return theMessage;
}
void getMessage(const int GET_MESSAGE)
{
char *received = NULL;
char theMessage[100];
/* Subtract 1 from the size, for the terminating '\0' */
received = search_value(llist, theMessage, sizeof(theMessage) - 1);
printf("%s", received);
}
the array you are returning is local to that function. Either the calle function shall provide the array in which it expects the values or use static array.

Resources