1.While I am trying to display conv it is not showing anything, but when i print one one element using subscript i am able to see the contents.
2. Program to convert decimal to binary, octal, hexadecimal
#include<stdio.h>
int main()
{
convbase(23,2);
return 0;
}
int convbase(int num, int base)
{
char conv[33] = {' '};
char *ptr = &conv[32];
conv[32] = '\0';
do
{
*--ptr = "0123456789ABCDEF"[num % base];
num = num/base;
}while(num);
if(base == 16)
{
*--ptr = 'x';
*--ptr = '0';
}
if(base == 8)
{
*--ptr = '0';
}
printf("Decimal to base %d is :\t%s\n",base,conv);
return 0;
}
change
printf("Decimal to base %d is :\t%s\n",base,conv);
to
printf("Decimal to base %d is :\t%s\n",base,ptr);
or
move the contents (ptr - to end of string) to start of conv array
another alternative is to instead of writing from end of conv to write from start and then when you are done call strrev() to reverse it.
printf("Decimal to base %d is :\t%s\n",base,strrev(conv));
You are filling your array from the end towards the front. In your example, the bit string is in the array elements 27...31. Thus, the 1st element contains \0, and the char array will be considered as an empty string, and nothing is printed.
You can check this easily by setting a breakpoint at the print statement.
You most propably assume that the following line initialises conv to all blanks:
char conv[33] = {' '};
This is not the case. With the above code conv has its first byte set to blank and all other bytes set to 0. So the result would only be printed if it had at least 31 digits.
You might consider using the follwong code to intialise conv:
char conv[33] = {0}; /* default init: set conv to all zeros */
memset(conv, ' ', sizeof(conv) - 1); /* re-set all but the last to blank */
This line:
conv[32] = '\0';
is not needed anymore than.
I do agree with Reinhard Männer that using a debugger would have helped you a lot to finding this out by yourself.
I think you're doing one -- too much.
While building the string, ptr always points to where you're going to write the next character (if there is a next character). This place is always initialized with null bytes (except for conv[0], which is a space.
So when calling printf, ptr points to null bytes, which is an empty string.
ptr++ before printf should solve it.
I do agree with #alk.
You were initializing only the first element of the array with blank and other elements were initialized to 0 because of which you were getting blank line.
Actually line is not blank, printf prints only first character which is blank ' ' and when it encounter 0 it stops.
You can verify it by replacing ' ' with any other character. ofcourse except '\0'
Related
i'm currently trying to debug my program over UART by printing the values of some variables at specific points. My issue is with printing two char arrays. The order in which i print them seems to have an effect on if it prints. The declarations of the arrays are in a struct in a header file as follows-
//header file
typedef struct
{
char latitude[10];
char longitude[11];
}NMEA_RMC_t;
NMEA_RMC_t rmc;
The char arrays are manipulated in another function after parsing data from an input. They are not updated with an interrupt, although there are interrupts elsewhere in the program. In the main code if i print them as follows-
//main program loop
printf("lat: %s \t long: %s \n", rmc.latitude, rmc.longitude);
the output to the terminal is this-
lat: +50.71735 long:
whereas if i print them in a different order like this-
printf("long: %s \t lat: %s \n", rmc.longitude, rmc.latitude);
i get this output.
long: -001.39118 lat:
also if i split the printing up into two separate printf statements, only the first print statement correctly prints the char array. I haven't had to ask for help on here before but this has had me stuck for a good week now. Any help would be massively appreciated! cheers.
edit
The part of the program that writes into the array is this. its essentially the same for the latitude and longitude array.
/* now we are in first char of latitude */
/* copy latitude chars */
strlcpy ((char*)lat, (const char*)ptr_to_comma, 10 );/*copies most size-1, null terminated*/ //changed 11 to 10
/* default latitude presentation is ddmm.mmmmm
we need to change it to dd.mmmmmmm
*/
unsigned char ind;
for (ind=0; ind<9; ind++)
{
if (*ptr_to_comma == '.')
{
ptr_to_comma++;//step over '.'
}
if ( ind==2 )
{
lat[ind++]='.';
}
lat[ind] = *ptr_to_comma;
ptr_to_comma++;
}
lat[10] = '\0'; //terminate
/* now lat == dd.mmmmmmm */
ptr_to_comma++; /*step over comma to the NS-indicator*/
/*catch NorthSouth-indicator and step*/
if ( *ptr_to_comma == 'N'){ /*if we are in the North*/
sign = '+';
rmc.ns_indicator = 'N';
} else if ( *ptr_to_comma == 'S'){ /*else we are in the South*/
sign = '-';
rmc.ns_indicator = 'S';
}
ptr_to_comma++;//step over NS-indicator
ptr_to_comma++;//step over comma to the longitude field
/* dd.mmmmmmm to dd.ddddddd */
_convert_minutes( (unsigned char*) lat+3 );
/* copy latitude with sign to the rmc-struct */
rmc.latitude[0] = sign;
strcpy ( (char*)rmc.latitude+1, (const char*)lat);
rmc.latitude[10]='\0';
essentially it is parsing the information from a stream of data coming in.
For %s to work correctly, the char array must have a NUL-terminator \0 which signifies the end of the string.
If you don't leave room for that, the behaviour of your program is undefined.
You need to initialise the arrays yourself - don't rely on the compiler to do it.
Get your debugger out and check the memory associated with rmc at the point of the printf.
Your code for converting the strings and putting them in the struct is inadvertently placing a '\0' character at the beginning of rmc.longitude. The code then goes on the fill the rest of the array with the correct value, but the printf() function sees rmc.longitude as a zero-length string and ignores what follows.
It is an an off-by-one error. rmc.latitude[10]='\0'; places a 0 in the 11th position of the rmc.latitude array, but this array was declared to only have 10 positions. What is actually happening instead is rmc.longitude[0] is getting the '\0' character, as it is adjacent in memory.
I want to write a program that gets the first half of a string 'ch1' and puts it in a string 'ch3' then gets the first half of another string 'ch2' and concatenates it in 'ch3' "puts is in the end of ch3" but when I execute it, it gives me weird output for ch3 ..
for example :
ch1 ="123"
ch2 ="azertyuiop"
the result :
ch3 ="1<3rdweirdletter>azert"
This is my code :
int main()
{
char ch1[200],ch2[200],ch3[200];
puts("give 'ch1' ");
gets(ch1);
puts("give 'ch2' ");
gets(ch2);
strncpy(ch3,ch1, strlen(ch1)/2 );
strncat(ch3,ch2, strlen(ch2)/2 );
printf("a half \"%s\" + a half \"%s\" gives \"%s\"",ch1,ch2,ch3);
return 0;
}
I would appreciate if someone helps me.
Thanks
You can either initialize ch3[] to be all zeroes: char ch3[200] = { 0 };
Or you can manually place the null-terminator (the character '\0') on ch3 after copying the first half of ch1 to it:
strncpy(ch3, ch1, strlen(ch1) / 2);
ch3[strlen(ch1)/2] = '\0';
strncat(ch3, ch2, strlen(ch2) / 2);
This is needed because strings in C need to be null-terminated (meaning you need a value of 0 after the last character of the string to mark the end of the string). The function strncpy(s, ct, n) only pads with zeroes if ct has less characters than n (not your case), therefore, if you don't add the null character manually, strncat will think that ch3 is much longer. It will search for the first zero in memory after ch3's start and only there it will concatenate what you wanted. That's where those weird characters come from.
I have a very simple function to convert a 3 char string representing a bit string to a decimal number:
int bin3_to_dec(char *bin) {
int result;
result=0;
printf("string: %s\n", bin);
printf("c0: %c\n", bin[0]);
printf("c1: %c\n", bin[1]);
printf("c2: %c\n", bin[2]);
if ((strcmp(&bin[0], "1") == 0))
result += 4;
if ((strcmp(&bin[1], "1") == 0))
result += 2;
if ((strcmp(&bin[2], "1") == 0))
result += 1;
printf("result: %d\n", result);
return result;
}
When I run the program and feed this function the string 111 it should calculate 7. Instead it outputs this:
string: 111
c0: 1
c1: 1
c2: 1
result: 1
Why is it not calculating the correct value? Why is only the third condition successfully passing?
Your string bin equal "111" really consists of four chars - that is '1', '1', '1', '\0' where the 4th char has the value zero which terminates (i.e. ends) the string.
So &bin[0] is the string "111"
and &bin[1] is the string "11"
and &bin[2] is the string "1"
So what your code is actually doing is the same as:
if ((strcmp("111", "1") == 0))
result += 4;
if ((strcmp("11", "1") == 0))
result += 2;
if ((strcmp("1", "1") == 0))
result += 1;
Only the last compare results in true so resultbecomes 1
&bin[0] is actually a pointer to a character array starting from 0th index which is 111. So, your first comparison fails. Similarly for second. But in your third comparison, &bin[2] is a pointer to character array starting from 2nd index which is 1 and hence it add 1 to result. So to make your code work:
you can check if(bin[0] == '1') // Here you compare the character at bin[0] and it is equal to 1 and so here the condition gets fulfilled.
C does not detect the end of a string until it encounters a null (i.e. \0). When you pass "111" into your function, you are actually passing a pointer to a block of memory that looks like this: "111\0". Thus, when you pass the address of bin[0] into strcmp(), strcmp operates on the full string "111". When you pass the address of bin[1] into strcmp(), strcmp operates on the string "11". Only when you pass the address of bin[2] into strcmp() do you get the behavior you were expecting, because in that case the next character in memory is a null.
if (bin[0] == '1') result += 4;
if (bin[1] == '1') result += 2;
if (bin[2] == '1') result += 1;
please note that &bin[0] is the same as bin
bin[0] is the first element
&bin[0] is a pointer to the first element just like bin
Have you tried printing &bin[1] (for example) as a string, instead of the individual characters? Because that's how strcmp() is going to see them.
In you do that, strcmp(&bin[0], "1") is clearly always non-zero, because &bin[0] is the full input string and (in our example) "111" is not at all like "1". Strings run until the null-terminator character.
You can use direct character comparisons (bin[0] == '1'), copy the character to a null-terminated string of its own, or (destructively) work from right to left and insert the null character ('\0') after the character that interests you. But you can't compare the middle of a string as a single character.
As mentioned by others, you are confusing those strings. The three of them are strings, however, string in java is an array of chars. So when you mean the string "1" using &bin[0], you are actually comparing "111". Why? Pointer to an array of chars make a string with the chars in this array starting where your pointer shows and continues to the end.
So when you point at the first letter you get "111", when you point at the second letter you get "11" and when you point at the last character you get "1", thats why your sum is 1. You can try to pass as argument the string "1111", you can see that your result is 0 intead of 1.
Your code seems somehow baffled around a function call of strcmp(), which isn't needed and would consistently return non-zero for any comparison between the string literal "1" and any "sub-string" pointed to in your code (&bin[0], &bin[1]), except for the one-printable-member-string &bin[2], if also "1". Let's have a walk-through.
As you have properly written in your function prototype, the pointer to the first element of the character array is being passed by value to your called function and copied as its argument. This is the "mechanism" for the part of memory populated by the array pointed to, to become visible by the called function, if its "upper bound" is known.
There are two means of having its upper bound known:
Passing the char array size as additional argument to the function, or
Null-terminating the char array in the calling function, so the called function can interpret it as string, which is your choice. The called function can either use strlen() to determine string length (size), or step through it, incrementing the counter, until a null-character is reached, and read size from the counter.
If the calling function already receives the array as a null-terminated string of '0' and '1' characters, the second looks more practical.
Allowing for up to as many characters as allowed by the storage capacity of the return data type of the called function (in this case int) clarifies the problem and simplifies the code. The caller function should guard against overflow.
The called function should only compare every array member's ASCII value with '1' and convert if equal.
For this strcmp isn't needed.
Please see the comments in this demonstration code, based on your post:
#include <stdio.h>
#include <string.h>
#define BPB 8 //bits per byte
int bin_to_dec(char *bin) //called function
{
int result=0;
int l = (int)strlen(bin);
for (int i = 0; i < l; i++){
printf("c%d: %c\n", i, bin[i]);
if(bin[i] == '1') //compare value of the i-th element
result += 1<<(l - i - 1); //convert to power-of-two and add to the result
}
return result;
}
int main(int argc, char *argv[]) //calling function
{
size_t siz = BPB*sizeof (int); //size for each char to represent one bit
char s[siz + 1]; //characters, each representing one bit + terminating '\0'
if((argc < 2)||(argc > 2)) //fail-safe check for correct count of arguments
return 1;
size_t len = strlen(argv[1]) ; //get length of the input string
if ( len > siz ) //check against too long input which would cause overflow
return 2;
strncpy(s, argv[1], len);
s[len] = '\0'; //appending the terminating null-character
for(int i = 0; i < (int)len; i++)
if((s[i] < '0')||(s[i] > '1')) //fool-proof check against 'off-limit' input
return 3;
printf("decimal: %d\n", bin_to_dec(s));
return 0;
}
Okay I have two problems with my solution to this problem, I was hoping I could get some help on. The problem itself is being able to print out #s in a specific format based on user input.
My questions are:
When I input 7, it outputs the correct solution, but when I output 8 (or higher), my buffer, for whatever reason add some garbage at the end, which I am unsure why it happens. I would add a picture but I don't have enough rep points for it :(
In my code, where I've inputted **HELPHERE**, I'm unsure why this gives me the correct solution. I'm confused because in the links I've read (on format specifiers) I thought that the 1 input (x in my case) specified how many spaces you wanted. I thought this would've made the solution x-n, as each consequent row, you'd need the space segment to decrease by 1 each time. Am I to understand that the array somehow reverses it's input into the printf statement? I'm confused because does that mean since the array increases by 1, on each subsequent iteration of the loop, it eats into the space area?
int main(void){
printf("Height: ");
int x = GetInt();
int n = 1;
int k=0;
char buff[x]; /* creates buffer where hashes will go*/
while(n<=x){ /* stops when getint value is hit*/
while(k<n) /* fill buffer on each iteration of loop with 1 more hashtag*/
{
buff[k] = '#';
k++;
}
printf("%*s",x, buff); /*makes x number of spaces ****HELPHERE*****, then prints buffer*/
printf(" ");
printf("%s\n",buff); /*prints other side of triangle */
/*printf("%*c \n",x-n, '\0');*/
n++;
}
}
Allocate enough memory and make sure the string is null terminated:
char buff[x+1];//need +1 for End of the string('\0')
memset(buff, '\0', sizeof(buff));//Must be initialized by zero
Print as many blanks as requested by blank-padding an empty string:
printf("%*s", x, "");
※the second item was written by Jonathan Leffler.
In printf("%*s",x, buff);, buff in not null character terminated.
Present code "worked" sometimes as buff was not properly terminated and the result was UB - undefined behavior. What likely happened in OP's case was that the buffer up to size 7, fortunately had '\0' in subsequent bytes, but not so when size was 8.
1) As per #BLUEPIXY, allocated a large enough buffer to accommodate the '#' and the terminating '\0' with char buff[x+1];
2) Change while loop to append the needed '\0'.
while (k<n) {
buff[k] = '#';
k++;
}
buff[k] = '\0';
3) Minor:insure x is valid.
if (x < 0) Handle_Error();
char buff[x];
4) Minor: Return a value for int main() such as return 0;.
Consider a char array like this:
43 234 32 32
I want the last value that is 32 in integer form.
The string size/length is not known. In the above example there are 4 numbers, but the size will vary.
How can this be done?
i have copied these value from the file onto char array.now i want the last number in integer variable
When you were copying,add a counter of # of characters copied. Then do this
int count = 0;
char c;
while(c = readCharFromFile()) {
array[count++] = c;
}
int last = array[count - 1];
There are many ways to solve this.
Convert every token (space delimited string) into a number and when the tokens run out return the last value converted.
Scan the line for tokens until you get to the end and then convert the last token into a number.
Start at the end of the line. Skip spaces and store digits until the first space is encountered and then convert the result to a number.
Split the string into an array of strings and convert the last one into a number.
I could go on and on but you get the idea I hope.
int getLastInt(char *data)
{
size_t i = strlen(data);
if(!i--) return -1; // failure
for(;i;--i)
{
if(data[i] == ' ')
{
return atoi(&data[i+1]);
}
}
return -1; // failure
}
Should work as long as the data has a space + actual text.
You could also skip the strlen and just loop forward, which could be faster depending on your system's strlen.
If there is no trailing whitespace on the line:
int last_int(const char *s)
{
const char *ptr = strrchr(s, ' ');
if (ptr == NULL) {
ptr = s;
} else {
ptr++;
}
return atoi(ptr);
}
If there can be trailing whitespace, then you'll need to do something like what ProdigySim suggested, but with more states, to walk backwards past the trailing whitespace (if any), then past the number, then call atoi(). No matter what you do, you'll need to watch out for boundary conditions and edge cases and decide how you want to handle them.
I guess you want to use a combination of strtok_r and atoi