I have a very simple code:
secret[]="abcdefgh";//this is declared in different function and is random word
int len=strlen(secret);//ofc it is 8 in this case
char word[len];
for(int a=0;a<len;a++){//expecting this will put '_' at positions 0-7
word[a]='_';
}
printf("%d %s",(int)strlen(word),word);
However, strlen(word) returns 11 and word contains "________� #", thus there is some obvious memory leak I can't see. Any idea?
This character array initialized by a string literal
secret[]="abcdefgh";
has 9 elements because it also includes the terminating zero of the string literal. So the definition above is equivalent to
secret[9]="abcdefgh";
Function strlen returns the number of elements of a character array that are before the terminating zero. So in this declaration
int len=strlen(secret);
variable len is initialized by 8
As result declaration
char word[len];
is equivalent to
char word[8];
In this loop
for(int a=0;a<len;a++){//expecting this will put '_' at positions 0-7
word[a]='_';
}
all elements of the aray are set to '_'. The arry does not have the terminating zero. So applaying function strlen to the array has undefined behaviour.
You could change the loop the following way
int a = 0;
for(;a<len - 1;a++){//expecting this will put '_' at positions 0-7
word[a]='_';
}
word[a] = '\0';
In this case function strlen would return number 7 and the program would be well-formed.
You just need to nul terminate the string, increase len by 1 and nul terminate your string.
#include <stdio.h>
#include <string.h>
int main(void)
{
char secret[]="abcdefgh";
int len=strlen(secret);
char word[len+1];
for(int a=0;a<len;a++)
{
word[a]='_';
}
word[a]=0; //or word[a]='\0'
printf("%d %s",(int)strlen(word),word);
return 0;
}
Regarding memory leak yes it can.
At first glance it seems you have forgot to put null at the end of your char array (pointer).
From my experience this leads to buffer overruns or stack corruption .
One addition and one modification
char word[len]; needs to be changed with char word[len+1];
Add a line world[len] = '\0'; before the last printf line.
That will be it
No space for the '\0'.
// "abcdefgh"
// 01234567
You need to define word with space for the NUL terminator.
char word[len + 1];
// "abcdefgh"
// 012345678 -- word[8] gets '\0'
Related
I wanted to test things out with arrays on C as I'm just starting to learn the language. Here is my code:
#include <stdio.h>
main(){
int i,t;
char orig[5];
for(i=0;i<=4;i++){
orig[i] = '.';
}
printf("%s\n", orig);
}
Here is my output:
.....�
It is exactly that. What are those mysterious characters? What have i done wrong?
%s with printf() expects a pointer to a string, that is, pointer to the initial element of a null terminated character array. Your array is not null terminated.
Thus, in search of the terminating null character, printf() goes out of bound, and subsequently, invokes undefined behavior.
You have to null-terminate your array, if you want that to be used as a string.
Quote: C11, chapter §7.21.6.1, (emphasis mine)
s
If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.280) Characters from the array are
written up to (but not including) the terminating null character. If the
precision is specified, no more than that many bytes are written. If the
precision is not specified or is greater than the size of the array, the array shall
contain a null character.
Quick solution:
Increase the array size by 1, char orig[6];.
Add a null -terminator in the end. After the loop body, add orig[i] = '\0';
And then, print the result.
char orig[5];//creates an array of 5 char. (with indices ranging from 0 to 4)
|?|?|?|0|0|0|0|0|?|?|?|?|
| ^memory you do not own (your mysterious characters)
^start of orig
for(i=0;i<=4;i++){ //attempts to populate array with '.'
orig[i] = '.';
|?|?|?|.|.|.|.|.|?|?|?|?|
| ^memory you do not own (your mysterious characters)
^start of orig
This results in a non null terminated char array, which will invoke undefined behavior if used in a function that expects a C string. C strings must contain enough space to allow for null termination. Change your declaration to the following to accommodate.
char orig[6];
Then add the null termination to the end of your loop:
...
for(i=0;i<=4;i++){
orig[i] = '.';
}
orig[i] = 0;
Resulting in:
|?|?|?|.|.|.|.|.|0|?|?|?|
| ^memory you do not own
^start of orig
Note: Because the null termination results in a C string, the function using it knows how to interpret its contents (i.e. no undefined behavior), and your mysterious characters are held at bay.
There is a difference between an array and a character array. You can consider a character array is an special case of array in which each element is of type char in C and the array should be ended (terminated) by a character null (ASCII value 0).
%s format specifier with printf() expects a pointer to a character array which is terminated by a null character. Your array is not null terminated and hence, printf function goes beyond 5 characters assigned by you and prints garbage values present after your 5th character ('.').
To solve your issues, you need to statically allocate the character array of size one more than the characters you want to store. In your case, a character array of size 6 will work.
#include <stdio.h>
int main(){
int i,t;
char orig[6]; // If you want to store 5 characters, allocate an array of size 6 to store null character at last position.
for (i=0; i<=4; i++) {
orig[i] = '.';
}
orig[5] = '\0';
printf("%s\n", orig);
}
There is a reason to waste one extra character space for the null character. The reason being whenever you pass any array to a function, then only pointer to first element is passed to the function (pushed in function's stack). This makes for a function impossible to determine the end of the array (means operators like sizeof won't work inside the function and sizeof will return the size of the pointer in your machine). That is the reason, functions like memcpy, memset takes an additional function arguments which mentions the array sizes (or the length upto which you want to operate).
However, using character array, function can determine the size of the array by looking for a special character (null character).
You need to add a NUL character (\0) at the end of your string.
#include <stdio.h>
main()
{
int i,t;
char orig[6];
for(i=0;i<=4;i++){
orig[i] = '.';
}
orig[i] = '\0';
printf("%s\n", orig);
}
If you do not know what \0 is, I strongly recommand you to check the ascii table (https://www.asciitable.com/).
Good luck
prinftf takes starting pointer of any memory location, array in this case and print till it encounter a \0 character. These type of strings are called as null terminated strings.
So please add a \0 at the end and put in characters till (size of array - 2) like this :
main(){
int i,t;
char orig[5];
for(i=0;i<4;i++){ //less then size of array -1
orig[i] = '.';
}
orig[i] = '\0'
printf("%s\n", orig);
}
I'm using an array in this code because i need a string which should be always modified, that's why i'm not using a pointer, howewer everytime i run the code i get a strange behavior at the 31th iteration.
code
int i = 0;
char name[100];
srand(getpid());
while(i<100) {
name[i] += (char)'A'+(rand()%26);
printf("%d strlen\n", i+1);
printf("%s\n", name);
printf("/////\n");
i++;
}
output
/////
30 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOY
/////
31 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJ
/////
32 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJWttime
/////
33 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW�time
/////
34 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW��ime
/////
35 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW���me
/////
36 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW����e
/////
37 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW�����
In other words it prints always ttime as the 31th character and then the code overwrites each character of that word and i get question mark as a result.
Going on the things get even worse look at the final output
100 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW�����K��ȶ������MKRLHALEV�SNNRVWNOEXUVQNJUHAEWN�W�YPMCW�N�PXHNT��0�
/////
Why does this happen?
Well you are printing garbage value. What the behavior will be is not known.(Undefined behavior) By that I mean, it may be the case that those garbage values (added with your random number) may be ascii values of some characters or may be those are some non-printables. You should initialize the char array (with \0's - that will serves two purpose, Providing \0 for the running string and also you can add and be sure it will be a printable) or just assign it.
name[i] = 'A'+(rand()%26);
Also put a \0 in the end of the string. Otherwise it will try to access array index out of bound until it finds \0 and it will invoke undefined behavior.
31 is not something special - it can be anything the very next time you run it.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
size_t i = 0;
char name[100]={0}; // = "";
srand(getpid());
while(i<99) { // till 99 making sure you won't overwrite the last NUL
name[i] ='A'+(rand()%26);
printf("%d strlen\n", i+1);
printf("%s\n", name);
printf("/////\n");
i++;
}
return 0;
}
Note that we have looped till 98th index because there is NUL terminating character in the 99th index.
char name[100]; is not a string by default. It is just another 100 element char array.
In C a string is a always carrying (at least) one '\0' character to mark the end of the string. printf(), mostly all str*() functions and many other functions rely on this terminating '\0'.
Also what is the idea behind adding to the array elements?
name[i] += ...
Their values are not set, they are garbage. Even worth, adding to them means reading uninitialised memory 1st, which in turn provokes undefined behaviour.
So to fix your code drop the addition add the terminator by hand:
while (i < 99) {
name[i] = (char) 'A' + (rand() % 26);
name[i + 1] = '\0';
Or go for the lazy approach any initialising name to all '\0' even before starting:
char name[100] = ""; /* or ... = {0}; */
(this would allow you to stick to doing name[i] += .... Still, as all elements are 0, adding is of no use.)
In any case do not loop until the array last element (100 here), but always one less as the last element is reserved for the terminating '\0'.
If the char name[100] array is a local variable inside a function, its initial value is undefined. So it will contain whatever random junk was in that chunk of memory before.
Therefore when you are doing
name[i] += (char)'A'+(rand()%26);
you are actually doing
name[i] = RANDOM JUNK + (char)'A'+(rand()%26);
I am trying to make function that compares all the letters from alphabet to string I insert, and prints letters I didn't use. But when I print those letters it goes over and gives me random symbols at end. Here is link to function, how I call the function and result: http://imgur.com/WJRZvqD,U6Z861j,PXCQa4V#0
Here is code: (http://pastebin.com/fCyzFVAF)
void getAvailableLetters(char lettersGuessed[], char availableLetters[])
{
char alphabet[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int LG,LG2,LA=0;
for (LG=0;LG<=strlen(alphabet)-1;LG++)
{
for(LG2=0;LG2<=strlen(lettersGuessed)-1;LG2++)
{
if (alphabet[LG]==lettersGuessed[LG2])
{
break;
}
else if(alphabet[LG]!=lettersGuessed[LG2] &&LG2==strlen(lettersGuessed)-1)
{
availableLetters[LA]=alphabet[LG];
LA++;
}
}
}
}
Here is program to call the function:
#include <stdio.h>
#include <string.h>
#include "hangman.c"
int main()
{
int i = 0;
char result[30];
char text[30];
scanf("%s", text);
while(i != strlen(text))
{
i++;
}
getAvailableLetters(text, result);
printf("%s\n", result);
printf ("%d", i);
printf ("\n");
}
Here is result when I typed in abcd: efghijklmnopqrstuvwxyzUw▒ˉ
If you want to print result as a string, you need to include a terminating null at the end of it (that's how printf knows when to stop).
for %s printf stops printing when it reaches a null character '\0', because %s expects the string to be null terminated, but result not null terminated and that's why you get random symbols at the end
just add availableLetters[LA] = '\0' at the last line in the function getAvailableLetters
http://pastebin.com/fCyzFVAF
Make sure your string is NULL-terminated (e.g. has a '\0' character at the end). And that also implies ensuring the buffer that holds the string is large enough to contain the null terminator.
Sometimes one thinks they've got a null terminated string but the string has overflowed the boundary in memory and truncated away the null-terminator. That's a reason you always want to use the form of functions (not applicable in this case) that read data, like, for example, sprintf() which should be calling snprintf() instead, and any other functions that can write into a buffer to be the form that let's you explicitly limit the length, so you don't get seriously hacked with a virus or exploit.
char alphabet[]={'a','b','c', ... ,'x','y','z'}; is not a string. It is simply an "array 26 of char".
In C, "A string is a contiguous sequence of characters terminated by and including the first null character. ...". C11 §7.1.1 1
strlen(alphabet) expects a string. Since code did not provide a string, the result is undefined.
To fix, insure alphabet is a string.
char alphabet[]={'a','b','c', ... ,'x','y','z', 0};
// or
char alphabet[]={"abc...xyz"}; // compiler appends a \0
Now alphabet is "array 27 of char" and also a string.
2nd issue: for(LG2=0;LG2<=strlen(lettersGuessed)-1;LG2++) has 2 problems.
1) Each time through the loop, code recalculates the length of the string. Better to calculate the string length once since the string length does not change within the loop.
size_t len = strlen(lettersGuessed);
for (LG2 = 0; LG2 <= len - 1; LG2++)
2) strlen() returns the type size_t. This is some unsigned integer type. Should lettersGuessed have a length of 0 (it might have been ""), the string length - 1 is not -1, but some very large number as unsigned arithmetic "wraps around" and the loop may never stop. A simple solution follows. This solution would only fail is the length of the string exceeded INT_MAX.
int len = (int) strlen(lettersGuessed);
for (LG2 = 0; LG2 <= len - 1; LG2++)
A solution without this limitation would use size_t throughout.
size_t LG2;
size_t len = strlen(lettersGuessed);
for (LG2 = 0; LG2 < len; LG2++)
In my code below:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define BLOCKSIZE 256;
int main()
{
char text[BLOCKSIZE];
char *new_line;
new_line=strcpy(text,"hello");
int i;
for(i=0;i<sizeof(text)/sizeof(char);i++)
{
printf("%c",*(new_line+i));
}
return 0;
}
I am trying to print the string "hello" on screen using a pointer which points to the address of the char array text. But in my code I get the string hello continued by some garbage values and then leads to core dumped. Can anyone show me the right way? Thanks
for(i=0;i < sizeof(text)/sizeof(char);i++)
The size of text is 256 bytes as you have allocated 256 bytes to it. sizeof(text)/sizeof(char) would return a value much greater than the size of "hello". That is why the loop is printing garbage values after "hello". You should use i < strlen(text) instead.
You are printing out all 256 characters of your text array. You only want to iterate up to the length of the string, like this:
for(i = 0; i < strlen(text); i++)
{
...
}
As well stated by #tourniquet_grab, code is printing beyond the end of "Hello"
Code copies "Hello" into the ample sized text[], but only the first 6 char (up to and including the terminating null character '\0'). The pointer returned by strcpy() is the address of the first char of text. The remaining 250 char of text has not been initialized. So the following prints "Hello", a '\0' and 250 pieces of junk.
new_line = strcpy(text,"hello");
for(i=0;i<sizeof(text)/sizeof(char);i++) {
printf("%c",*(new_line+i));
}
More sensible to print the string contents of new_line - only up to, but not including the terminating null character '\0'. This method will change the pointer of new_line.
new_line = strcpy(text,"hello");
// Continue looping until \0 reached
while (*new_line) {
printf("%c", *new_line++);
}
Minor points:
sizeof(char) is always 1. Rarely useful to code that. If anything, code sizeof(text)/sizeof(text[0]).
Rather than printf("%c",*new_line++);, could use fputc(*new_line++, stdout) or other 1 char functions like putc()
reverser() reverses a cstring (not in place). 99% of the time it works but some input corrupts it for example it appears if aStr2[] is assigned a string made up of the same character it will have an error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* reverser(const char *str);
int main()
{
char aStr[] = "aaa";
char aStr2[] = "cccccc";
printf("%s %s", aStr, aStr2);
char* tmp = reverser(aStr2);//tmp now has garbage
printf("\n%s", tmp);
printf(" %s", aStr2);
return 0;
}
char* reverser(const char *str)
{
char* revStr = (char*)malloc(strlen(str));
int i;
for(i = strlen(str)-1; i >= 0; i--)
{
revStr[strlen(str)-1-i] = str[i];
}
return revStr;
}
Gives
aaa cccccc
cccccc9 cccccc
Process returned 0 (0x0) execution time : 0.068 s
Press any key to continue
Notice the 9 that shouldn't be there.
Change this malloc to strlen(str) + 1 , plus 1 for '\0'
char* revStr = (char*)malloc(strlen(str) + 1);
and after the for loop
revStr[strlen(str)+1] = '\0';
Your problem is that you don't put the string terminator in your reversed string. All strings in C are actually one extra character that isn't reported by strlen, and that is the character '\0' (or plain and simple, a zero). This tells all C functions when the string ends.
Therefore you need to allocate space for this extra terminator character in your malloc call, and add it after the last character in the string.
There are also a couple of other problems with your code, the first is that you should not cast the return of malloc (or any other function returning void *). Another that you have a memory leak in that you do not free the memory you allocate. This last point doesn't matter in a small program like the one you have here, but will be an issue in larger and longer running programs.
You haven't null-terminated your reversed string. You need to set the final index of revStr[] to 0.