I didn't used C for a lot of time, and now I have to modify a little piece of code. There one thing I can't understand:
char filename[20];
filename[0] = '\0';
for (j=0; j < SHA_DIGEST_LENGTH; j++){
sprintf(filename + strlen(filename),"%02x",result[j]);
}
In the first line a string of 20 characters is dleclared.
In the second line the first char is set to '\0', so is an empty string, I suppose.
In the for loop I don't understand the "sum" between filename and its length... The firs parameter of sprintf should be a buffer where to copy the formatted string on the right. What is the result of that sum? It seems to me like I'm trying to sum an array and an integer...
What I'm missing?
It's pointer arithmetic. strlen returns the number of characters before the NUL terminator. The result of the addition will point to this terminator. E.g. if the current string is "AA" (followed by a NUL), strlen is 2. filename + 2 points to the NUL. It will write the next hex characters (e.g. BB) over the NUL and the next character. It will then NUL-terminate it again (at filename + 4). So then you'll have "AABB" (then NUL).
It doesn't really make sense though. It wastes a lot of time looking for those NULs. Specifically, it's a quadratic algorithm. The first time, it examines 1 character, then 3, 5, 7, ..., 2 * SHA_DIGEST_LENGTH - 1) that . It could just be:
sprintf(filename + 2 * j,"%02x",result[j]);
There's another problem. A hexadecimal representation of a SHA-1 sum takes 40 characters, since a byte requires two characters. Then, you have a final NUL terminator, so there should be 41. Otherwise, there's a buffer overflow.
Why dont you declare
char filename[SHA_DIGEST_LEN*2 +1]; /* And +1 if you want to have the NULL terminating char*/
This is because SHA1 digest length is 20 bytes, if you were just to print the digest then you may probably not want the additional memory but since you want hexadecimal string of the digest you can use the above declaration.
A strlen operation returns lenghth of string till a null terminating character is encountered.
So basically when you do the following :
sprintf(filename + strlen(filename),"%02x",result[j]);
In the first interation filname is copied with 2 bytes of the hexadecimal representation of the first byte of the sha-1 digest. Eg. Say that is AA, now you need to move your pointer two places to copy the next byte.
After second iteration it becomes AABB.
After the 20th iteration you have the entire string AABBCC......AA[40 bytes] and +1 if you need the '\0' which is the NULL termination character.
First iteration, when j = 0, you will write 3 chars (yes, including the '\0' terminating the string) onto the beginning of filename, since strlen() then returns 0.
Next round, strlen() returns 2, and it will continue writing after the first two chars.
Be careful for stepping outside the 20 char space allocated. Common mistake is to forget the space required for the string terminator.
EDIT: make sure that SHA_DIGEST_LENGTH is not greater than 9.
you are adding strlen(filename) only to do concatenation of result[j]
Each iteration concatenates the current result[j] at the end of filename so each time you need to know to offset within the filename where the concatenation should take place.
Replace the code with:
char filename[SHA_DIGEST_LENGTH*2+1];
for (j=0; j < SHA_DIGEST_LENGTH; j++){
sprintf(filename + 2*j,"%02x",result[j]);
}
Faster, simpler, and the bugs are gone.
Related
I'm working with char arrays in C. I'm setting the size in a previous step. When I print it out it clearly shows the num_digits as 1.
But then when I put it in to set the size of a char array to make it a char array of size num_digits, its setting the size of the array as 6.
In the next step when I print strlen(number_array), it prints 6. Printing it out I get something with a lot of question marks. Does anyone know why this is happening?
int num_digits = get_num_digits(number);
printf("Num digits are %d\n", num_digits);
char number_array[num_digits];
printf("String len of array: %d\n", strlen(number_array));
You need to null terminate your array.
char number_array[num_digits + 1];
number_array[num_digits] = '\0';
Without this null terminator, C has no way of know when you've reached the end of the array.
just use 'sizeof' instead of 'strlen'
printf("String len of array: %d\n", sizeof(number_array));
There are a couple possible issues I see here:
As noted in Michael Bianconi's answer, C character arrays (often called strings) require null terminators. You would explicitly set this this with something like:
number_array[number + 1] = '\0'; /* See below for why number + 1 */
Rather than just setting the last element to null, pre-initializing the entire character array to nulls might be helpful. Some compilers may do this for you, but if not you'll need to do this explicitly with something like:
for (int i = 0; i < num_digits + 1; i ++) number_array[i] = '\0';
Note that with gcc I had to use C99 mode using -std=c99 to get this to compile, as the compiler didn't like the initialization within the for statement.
Also, the code presented sets the length of the character array to be the same length as number's length. We don't know what get_num_digits returns, but if it returns the actual number of significant digits in an integer, this will come up one short (see above and other answer), as you need an extra character for the null terminator. An example: if the number is 123456 and get_number_digits returns 6, you would would need to set the length of number_array to 7, instead of 6 (i.e. number + 1).
char number_array[num_digits]; allocates some space for a string. It's an array of num_digits characters. Strings in C are represented as an array of characters, with a null byte at the end. (A null byte has the value zero, not to be confused with the digit character '0'.) So this array has room for a string of up to num_digits - 1 characters.
sizeof(number_array) gives you the array storage size. That's the total amount of space you have for a string plus its null terminator. At any given time, the array can contain a string of any length up to number_array - 1, or it might not contain a string at all if the array doesn't contain a null terminator.
strlen(number_array) gives you the length of the string contained in the array. If the array doesn't contain a null terminator, this call may return a garbage value or crash your program (or make demons fly out of your nose, but most computers fortunately lack the requisite hardware).
Since you haven't initialized number_array, it contains whatever happened to be there in memory before. Depending on how your system works, this may or may not vary from one execution of the program to the next, and this certainly does vary depending on what the program has been doing and on the compiler and operating system.
What you need to do is:
Give the array enough room for the null terminator.
Initialize the array to an empty string by making setting the first character to zero.
Optionally, initialize the whole array to zero. This is not necessary, but it may simplify further work with the array.
Use %zu rather than %d to print a size. %d is for an int, but sizeof and strlen return a size_t, which depending on your system may or may not be the same size of integers.
char number_array[num_digits + 1];
number_array[0] = 0; // or memset(number_array, 0, sizeof(number_array));
printf("Storage size of array: %zu\n", sizeof(number_array));
printf("The array contains an empty string: length=%zu\n", strlen(number_array));
I'm making a simple program in C, which checks the length of some char array and if it's less than 8, I want to fill a new array with zeroes and add it to the former array. Here comes the problem. I don't know why the last values are some signs(see the photo).
char* hexadecimalno = decToHex(decimal,hexadecimal);
printf("Hexadecimal: %s\n", hexadecimalno);
char zeroes [8 - strlen(hexadecimalno)];
if(strlen(hexadecimalno) < 8){
for(i = 0; i < (8-strlen(hexadecimalno)); i++){
zeroes[i]='0';
}
}
printf("zeroes: %s\n",zeroes);
strcat(zeroes,hexadecimalno);
printf("zeroes: %s\n",zeroes);
result
In C, strings (which are, as you are aware, arrays of characters) do not have any special metadata that tells you their length. Instead, the convention is that the string stops at the first character whose char value is 0. This is called "null-termination". The way your code is initializing zeroes does not put any null character at the end of the array. (Do not confuse the '0' characters you are putting in with NUL characters -- they have char value 48, not 0.)
All of the string manipulation functions assume this convention, so when you call strcat, it is looking for that 0 character to decide the point at which to start adding the hexadecimal values.
C also does not automatically allocate memory for you. It assumes you know exactly what you are doing. So, your code is using a C99 feature to dynamically allocate an array zeroes that has exactly the number of elements as you need '0' characters appended. You aren't allocating an extra byte for a terminating NUL character, and strcat is also going to assume that you have allocated space for the contents of hexadecimalno, which you have not. In C, this does not trigger a bounds check error. It just writes over memory that you shouldn't actually write over. So, you need to be very careful that you do allocate enough memory, and that you only write to memory you have actually allocated.
In this case, you want hexadecimalno to always be 8 digits long, left-padding it with zeroes. That means you need an array with 8 char values, plus one for the NUL terminator. So, zeroes needs to be a char[9].
After your loop that sets zeroes[i] = '0' for the correct number of zeroes, you need to set the next element to char value 0. The fact that you are zero-padding confuses things, but again, remember that '0' and 0 are two different things.
Provided you allocate enough space (at least 9 characters, assuming that hexadecimalno will never be longer than 8 characters), and then that you null terminate the array when putting the zeroes into it for padding, you should get the expected result.
char dev[20] = "dev_name";
char dest[32];
strncpy(dest,dev,sizeof(dev));
dest[sizeof(dev)-1] = 0;
What does dest[sizeof(dev)-1] = 0; means?
In your code, assuming size is analogous to sizeof,
dev_name[size(dec_name)-1] = 0;
dev_name[size(dec_name)-1] points to the last element of the array, remember C arrays use 0 based indexing.
Then, by definition, a string in c is exxentially a char array with null-termination, so if you want to use a char array as string, you must have the null-termination.
0 is the ASCII value of NUL or null. So, essentially, you're putting a null-terminator to the char array.
Does it mean all the element of that array are assigned zero?
No it does not mean this.
Assuming you meant strncpy(dest,dev_name,sizeof(dev_name)); /* Extra bracket */ and dev_name and sizeof in you last line; You are assigning NUL character to the last to mark the end of name array.
When you write a string literal like "foo", it is automatically NUL terminated by the compiler. When you take your own arrays, you sometimes need to mark the end of string manually.
From man strncpy
The strncpy() function is similar, except that at most n bytes of src
are copied. Warning: If there is no null byte among the first n bytes
of src, the string placed in dest will not be null-terminated.
Explicitly the null-termination is added to handle the warning case in your code snippet.
dev_name[0], dev_name[1], dev_name[2] etc are first, second, third ... characters of your string. Assuming device name has less than 31 characters, it is automatically NUL terminated after strncpy and you don't need to do anything.
If the name has exactly 31 character, last character character (32nd) is already '\0' (ascii code 0) and writing 0 again over it does not make any difference.
If the name has more than 31 character (corner case), last character character is not NUL and dev_name[sizeof(dev_name)-1] = 0; will make the name NUL terminated.
I tried to use sprintf to append a int, string and an int.
sprintf(str,"%d:%s:%d",count-1,temp_str,start_id);
Here, the value of start_id is always the same. The value of temp_str which is a char * increases every time. I get correct output for some time and then my sprintf starts printing junk characters between temp_str and startid. So my str get corrupted.
Can anyone explain this behavior ?
example
at count 11
11:1:2:3:1:2:3:1:2:3:1:21:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2
at count 8
8:1:2:3:1:2:3:1:2:3:1:21:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1:2:3:1�:2
I don't understand why and how "�" is appended to the string
Either temp_str is not null-terminated at some point or you've blown the buffer for str and some other memory access is affecting it.
Without seeing the code, it's a little hard to tell but, if you double the size of str and the problem behaviour changes, then it's probably the latter.
1> try to memset your str buffer with 0 befor using sprintf
2> The value of temp_str which is a char * increases every time
what do u mean by this ?
this should be normal charachter pointer which will point some string and that string should be null terminated and tha will be copied to str
3> the total size by combing all three argument should not be exceed the size of str buffer
It looks like the string temp_str isn't NUL-terminated. You can either terminate it before the call to sprintf, or if you know the length you want to print, use the %.*s formatting operator like this:
int str_len = ...; // Calculate length of temp_str
sprintf(str, "%d:%.*s:%d", count-1, str_len, temp_str, start_id);
You are running off the end of temp_str. Check your bounds and make sure it's null terminated. Stop incrementing sun you get to the end.
I have a little problem here with memcpy()
When I write this
char ipA[15], ipB[15];
size_t b = 15;
memcpy(ipA,line+15,b);
It copies b bytes from array line starting at 15th element (fine, this is what i want)
memcpy(ipB,line+31,b);
This copies b bytes from line starting at 31st element, but it also attaches to it the result for previous command i.e ipA.
Why? ipB size is 15, so it shouldnt have enough space to copy anything else. whats happening here?
result for ipA is 192.168.123.123
result for ipB becomes 205.123.123.122 192.168.123.123
Where am I wrong? I dont actually know alot about memory allocation in C.
It looks like you're not null-terminating the string in ipA. The compiler has put the two variables next to one another in memory, so string operations assume that the first null terminator is sometime after the second array (whenever the next 0 occurs in memory).
Try:
char ipA[16], ipB[16];
size_t b = 15;
memcpy(ipA,line+15,b);
ipA[15] = '\0';
memcpy(ipB,line+31,b);
ipB[15] = '\0';
printf("ipA: %s\nipB: %s\n", ipA, ipB)
This should confirm whether this is the problem. Obviously you could make the code a bit more elegant than my test code above. As an alternative to manually terminating, you could use printf("%.*s\n", b, ipA); or similar to force printf to print the correct number of characters.
Are you checking the content of the arrays by doing printf("%s", ipA) ? If so, you'll end up with the described effect since your array is interpreted as a C string which is not null terminated. Do this instead: printf("%.*s", sizeof(ipA), ipA)
Character strings in C require a terminating mark. It is the char value 0.
As your two character strings are contiguous in memory, if you don't terminate the first character string, then when reading it, you will continue until memory contains the end-of-string character.