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.
Related
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.
I have an archive file that looks like this:
!<arch>
file1.txt/ 1350248044 45503 13036 100660 28 `
hello
this is sample file 1
Now in here, the number 28 in the header is the file1.txt size. To get that number, I use:
int curr_char;
char file_size[10];
int int_file_size;
curr_char = fgetc(arch_file);
while(curr_char != ' '){
strcat(file_size, &curr_char);
curr_char = fgetc(arch_file);
}
// Convert the characters to the corresponding integer value using atoi()
int_file_size = atoi(file_size);
However, values in the file_size array change every time I run my code. Sometimes it's correct, but mostly not. Here are some examples of what I get for file_size:
?28`U
2U8U
28 <--- Correct!
pAi?28
I believe the problem is with my strcat() function, but not sure. Any help would be appreciated.
You shouldn't read the file character wise. There are higher level functions doing this. As larsmans already pointed out, you can use fscanf() for this task:
fscanf(arch_file, "%d", &int_file_size);
&curr_char is an int*, so you're copying over the bits of an int as if they represented a string.
You should be using scanf.
The expression &curr_char points to a single character (well, actually an integer as that's how you declared it). strcat looks for a string, and string as you should know are terminated by a '\0' character. So what strcat does in your case is use the &curr_char pointer as the address of a string and looks for the terminator. Since that is not found weird stuff will happen.
One way of solving this is to make curr_char an array, initialized to zero (the string terminator character) and read into the first entry:
char curr_char[2] = { '\0' }; /* Will make all character in array be zero */
...
curr_char[0] = fgetc(...);
There is also another problem, and that is that you are trying to concatenate into a string that is not initialized. When running your program, the array file_size can contain any data, it's not automatically zeroed out. This leads to the weird characters before the number. This is solved partially the same way as the above problem, by initializing the array:
char file_size[10] = { '\0' };
I'm confused as to what is causing this behavior in my program. I'm just trying to copy the contents of one char* array to another and instead of copying the element, but it's concatenating the strings in a strange way. I'm doing something like this:
char* a[50];
char* b[50];
for(int n=0; n<x; n++){
a[n] = malloc(sizeof(char) * (1 + strlen(b[n])));
strcpy(a[n], b[n]);
}
Has anyone experienced this before? I can post my output if that helps.
Thanks.
A few issues:
You loop while n < x. What is x? If x >= 50, you'll run off the end of your arrays. Your loop condition needs to protect against this possibility.
Also, remember that the memory returned by malloc is uninitialized. It is good that you are allocating an extra byte for the NULL terminator. What you are missing is the code that actually sets the value of the NULL terminator. The consequence of this is that your a[] strings are most likely not NULL-terminated (the last character is whatever random garbage that was previously stored in that byte). When you try to print them out or use a string function like strlen on it, you'll read past the end of the string and into whatever happens to be sitting in the memory range that follows.
Trying using strncpy, note that you have add the null termination character at the end of a[n], This way you are sure to know what you are copying rather relying on the assumption that b[n] has null terminating character.
Consider following case:
#include<stdio.h>
int main()
{
char A[5];
scanf("%s",A);
printf("%s",A);
}
My question is if char A[5] contains only two characters. Say "ab", then A[0]='a', A[1]='b' and A[2]='\0'.
But if the input is say, "abcde" then where is '\0' in that case. Will A[5] contain '\0'?
If yes, why?
sizeof(A) will always return 5 as answer. Then when the array is full, is there an extra byte reserved for '\0' which sizeof() doesn't count?
If you type more than four characters then the extra characters and the null terminator will be written outside the end of the array, overwriting memory not belonging to the array. This is a buffer overflow.
C does not prevent you from clobbering memory you don't own. This results in undefined behavior. Your program could do anything—it could crash, it could silently trash other variables and cause confusing behavior, it could be harmless, or anything else. Notice that there's no guarantee that your program will either work reliably or crash reliably. You can't even depend on it crashing immediately.
This is a great example of why scanf("%s") is dangerous and should never be used. It doesn't know about the size of your array which means there is no way to use it safely. Instead, avoid scanf and use something safer, like fgets():
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte ('\0') is stored after the last character in the buffer.
Example:
if (fgets(A, sizeof A, stdin) == NULL) {
/* error reading input */
}
Annoyingly, fgets() will leave a trailing newline character ('\n') at the end of the array. So you may also want code to remove it.
size_t length = strlen(A);
if (A[length - 1] == '\n') {
A[length - 1] = '\0';
}
Ugh. A simple (but broken) scanf("%s") has turned into a 7 line monstrosity. And that's the second lesson of the day: C is not good at I/O and string handling. It can be done, and it can be done safely, but C will kick and scream the whole time.
As already pointed out - you have to define/allocate an array of length N + 1 in order to store N chars correctly. It is possible to limit the amount of characters read by scanf. In your example it would be:
scanf("%4s", A);
in order to read max. 4 chars from stdin.
character arrays in c are merely pointers to blocks of memory. If you tell the compiler to reserve 5 bytes for characters, it does. If you try to put more then 5 bytes in there, it will just overwrite the memory past the 5 bytes you reserved.
That is why c can have serious security implementations. You have to know that you are only going to write 4 characters + a \0. C will let you overwrite memory until the program crashes.
Please don't think of char foo[5] as a string. Think of it as a spot to put 5 bytes. You can store 5 characters in there without a null, but you have to remember you need to do a memcpy(otherCharArray, foo, 5) and not use strcpy. You also have to know that the otherCharArray has enough space for those 5 bytes.
You'll end up with undefined behaviour.
As you say, the size of A will always be 5, so if you read 5 or more chars, scanf will try to write to a memory, that it's not supposed to modify.
And no, there's no reserved space/char for the \0 symbol.
Any string greater than 4 characters in length will cause scanf to write beyond the bounds of the array. The resulting behavior is undefined and, if you're lucky, will cause your program to crash.
If you're wondering why scanf doesn't stop writing strings that are too long to be stored in the array A, it's because there's no way for scanf to know sizeof(A) is 5. When you pass an array as the parameter to a C function, the array decays to a pointer pointing to the first element in the array. So, there's no way to query the size of the array within the function.
In order to limit the number of characters read into the array use
scanf("%4s", A);
There isn't a character that is reserved, so you must be careful not to fill the entire array to the point it can't be null terminated. Char functions rely on the null terminator, and you will get disastrous results from them if you find yourself in the situation you describe.
Much C code that you'll see will use the 'n' derivatives of functions such as strncpy. From that man page you can read:
The strcpy() and strncpy() functions return s1. The stpcpy() and
stpncpy() functions return a
pointer to the terminating `\0' character of s1. If stpncpy() does not terminate s1 with a NUL
character, it instead returns a pointer to s1[n] (which does not necessarily refer to a valid mem-
ory location.)
strlen also relies on the null character to determine the length of a character buffer. If and when you're missing that character, you will get incorrect results.
the null character is used for the termination of array. it is at the end of the array and shows that the array is end at that point. the array automatically make last character as null character so that the compiler can easily understand that the array is ended.
\0 is an terminator operator which terminates itself when array is full
if array is not full then \0 will be at the end of the array
when you enter a string it will read from the end of the array
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.