In my C program I am trying to copy an array of char's to another array whilst removing the first element (element 0).
I have written:
char array1[9];
char array2[8];
int i, j;
for(i = 1, j = 0 ; i < 10, j < 9; i++, j++){
array2[j] = array1[i];
}
printf(array2);
When I print array2, it gives me a stack overflow.
Any ideas?
Two issues:
First, when printing a string with printf, and working with other standard C string functions in general, your char arrays need to be null-terminated so the functions know where the string ends. You are also writing one past the end of your arrays.
Second, when using printf, it is almost always a bad idea to use the string you want to print as the format string. Use
printf("%s", array2);
instead. If you use printf as in the original example and array2 can be influenced by the user, then your program is likely vulnerable to a format string vulnerability.
Use memcpy():
memcpy( array2, &array1[1], 8 );
Thats easier.
Your string isn't null-terminated, so when its printed it continues printing characters past the 8 you've allocated looking for one but runs out of stack space before then. You're also writing to one character more than you've allocated and your conditions should be "combined" with && -- a , ignores the result of the first expression. You should also avoid using a string variable as the string formatter to printf.
Here's your code fixed:
char array1[10] = "123456789";
char array2[9];
int i, j;
for(i = 1, j = 0 ; i < 10 && j < 9; i++, j++){
array2[j] = array1[i];
}
printf("%s\n", array2);
You can also simplify the loop by using a single index variable i and indexing array2 with i+. You can also remove the loop entirely by using strncpy, but be aware that if n is less than the length of the string + 1 it won't add a null-terminator.
It's not necessary to use an extra array2 like
printf("%.8s",array1+1);
When you say printf(array2), it thinks it's printing a null-terminated string. Since there is (possibly) no \0 in array2, printf continues on past the end of array2, wandering into memory it isn't supposed to.
To further expand on marcog's answer: you are declaring array1 with 9 elements, 0-8, and then writing from 0-9 (10 elements). Same thing with array2.
Just use strcpy() (if they're both strings!) strcpy() wants a pointer to the source and a pointer to the destination. If you want to skip the first element of the source array just pass source + 1:
char source[] = "ffoo";
char dest[] = "barbar";
strcpy(dest, source + 1);
// now dest is "foo" (since the ending \0 is copied too)
printf("\n%s\n", dest);
Related
I am currently learning C and am trying to fill an array of strings with a loop as a simple exercise. I am just trying to fill all 4 elements with the word "Hello". When I print my array out I get output like this:
messages[0] = HelloHelloHelloHello
messages[1] = HelloHelloHello
messages[2] = HelloHello
messages[3] = Hello
For an odd reason, the first 3 elements have the word hello repeating mulitple times. I do not understand why this is happening.
Here is my code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char messages[4][5];
for(int i = 0; i < 4; i++){
//&messages[i] = (char *)malloc(5);
strcpy(messages[i],"Hello");
}
for(int i = 0; i < 4; i++){
printf("messages[%d] = %s\n", i, messages[i]);
}
return 0;
}
I also tried looking up way to do this, and I found something about using malloc, but I just kept getting compiler errors.
You have not allocated memory for the null terminator.
char messages[4][5]; should be char messages[4][6];
Since there is no null terminator. printf prints the character until null terminator is found.And also the last strcpy copies the \0 beyond the memory allocated by you. This is undefined behavior.
As mentioned in the other replies, the problem is in the statement
strcpy(messages[i], "Hello");
The array messages is declared as an array of four arrays of length five but the size of the string "Hello" is actually six characters; the terminating null character is an invisible part of the string. If you print the value of sizeof "Hello" you will get the value six.
If you just need an array of strings which you don't intend to change, you can declare your array as
const char *messages[] = {"Hello", "Hello", "Hello", "Hello"};
Here the length of the array is inferred from the initializer.
It is also a good idea to not hard code the length of the array in more then one place. In my own code I always use the array length macro
#define LEN(array) ((int) (sizeof (array) / sizeof (array)[0]))
With this you can write
for (int i = 0; i < LEN(messages); i++) {
...
}
If you then want to change the length of messages you only need to change the declaration.
Strings in C are terminated by a zero byte - that is, a byte containing zero. Thus, to hold a five character string you need to reserve six characters for it - five for the data and one for the terminator. If you increase the size of the second dimension of your array of characters to six instead of five it will work as you expected:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char messages[4][6];
for(int i = 0; i < 4; i++){
//&messages[i] = (char *)malloc(5);
strcpy(messages[i],"Hello");
}
for(int i = 0; i < 4; i++){
printf("messages[%d] = %s\n", i, messages[i]);
}
return 0;
}
I don't understand Why don’t we have to print strings in for loop ? In normal cases we need to print arrays in for loop. For example, if we want to print the array of integers. It will be like this:
int a[n];
for (i = 0; i < n; i++){
printf("%d", a[i]);
}
But for strings like:
char s[100] = " Hello ";
printf("%s\n", s);
it is enough to write the name of array.
EDIT: It seems like I didnt ask my question properly as some of you wrote answers which is not related to my question.I edit my question.
Strings terminate with the empty character '\0', that's how it is possible to know when a string ends even without explicitly passing its length.
The difference is that C-style strings (which are char arrays) are zero-terminated, whereas int arrays are normally not zero terminated.
Theoretically, you could also create an int array which is zero-terminated and print that in a loop:
int a[] = {5,7,3,0};
for (i=0;a[i]!=0;i++)
{
printf("%d",a[i])
}
However, the problem with zero-terminated int arrays is that the number 0 could be a meaningful value, so you cannot be sure that it really is the end of the array when you encounter that value. With strings, however, the ASCII-Code 0 does not represent a meaningful value, so you can be reasonably sure that you have reached the end of the string.
Your example is far from analogous. %d refers to a single integer, while %s refers to an entire (but still single) string.
You are not passing the size of the array n[] to printf either - rather you are calling printf n times. You are printing one int just as you are printing one string.
The actual string length is not known a priori, rather printf iterates the string until it encounters the \0 terminator. Equivalent to:
for( int i = 0; s[i] != '\0'; i++)
{
printf( "%c", s[i] ) ;
}
because
char s[100] = " Hello ";
is equivalent to:
char s[100] = { ' ', 'H', 'e', 'l', 'l', 'o', ' ', '\0' } ;
Strings are multiple characters all at once. You cannot ask for a specific character from a string. If you want to do so, you must refer to it as an array of chars like this
for (i = 0; i < n; i++){
printf("%c", s[i]);
}
It is because you are already providing the parameter which is "%s" to the printf function which already has a definition telling it how to print a string.
Hope it helps.
One of the reason is that char only takes 1 byte of memeory and when you just press a character, the first index of array is filled up completely and it moves on to the next one till it encounters NULL character. This is not the case with integer array where the size is more than 1 byte and is machine dependent. So you cannot escape the first index by just pressing the number less than the maximum range. If you try to do this, it will store your numbers in first index only and hence a for loop is required there.
I am trying to concatenate a random number of lines from the song twinkle twinkle. Into the buffer before sending it out because I need to count the size of the buffer.
My code:
char temp_buffer[10000];
char lyrics_buffer[10000];
char *twinkle[20];
int arr_num;
int i;
twinkle[0] = "Twinkle, twinkle, little star,";
twinkle[1] = "How I wonder what you are!";
twinkle[2] = "Up above the world so high,";
twinkle[3] = "Like a diamond in the sky.";
twinkle[4] = "When the blazing sun is gone,";
twinkle[5] = "When he nothing shines upon,";
srand(time(NULL));
arr_num = rand() % 5;
for (i=0; i<arr_num; i++);
{
sprintf(temp_buffer, "%s\n", twinkle[i]);
strcat(lyrics_buffer, temp_buffer);
}
printf("%s%d\n", lyrics_buffer, arr_num);
My current code only prints 1 line even when I get a number greater than 0.
There are two problems: The first was found by BLUEPIXY and it's that your loop never does what you think it does. You would have found this out very easily if you just used a debugger to step through the code (please do that first in the future).
The second problem is that contents of non-static local variables (like your lyrics_buffer is indeterminate. Using such variables without initialization leads to undefined behavior. The reason this happens is because the strcat function looks for the end of the destination string, and it does that by looking for the terminating '\0' character. _If the contents of the destination string is indeterminate it will seem random, and the terminator may not be anywhere in the array.
To initialize the array you simply do e.g.
char lyrics_buffer[10000] = { 0 };
That will make the compiler initialize it all to zero, which is what '\0' is.
This initialization is not needed for temp_buffer because sprintf unconditionally starts to write at the first location, it doesn't examine the content in any way. It does, in other words, initialize the buffer.
Update the buffer address after each print after initializing buffer with 0.
char temp_buffer[10000] = {0};
for (i=0; i<arr_num; i++) //removed semicolon from here
{
sprintf(temp_buffer + strlen(temp_buffer), "%s\n", twinkle[i]);
}
temp_buffer should contain final output. Make sure you have enough buffer size
You don't need strcat
I'm still new to programming but lets say I have a two dimensional char array with one letter in each array. Now I'm trying to combine each of these letters in the array into one array to create a word.
So grid[2][4]:
0|1|2|3
0 g|o|o|d
1 o|d|d|s
And copy grid[0][0], grid[0][1], grid[0][2], grid[0][3] into a single array destination[4] so it reads 'good'. I have something like
char destination[4];
strcpy(destination, grid[0][1]);
for(i=0; i<4; i++)
strcat(destination, grid[0][i]);
but it simply crashes..
Any step in the right direction is appreciated.
In C, the runtime library functions strcpy and strcat require zero terminated strings. What you're handing to them are not zero terminated, and so these functions will crash due to their dependency on that terminating zero to indicate when they should stop. They are running through RAM until they read a zero, which could be anywhere in RAM, including protected RAM outside your program, causing a crash. In modern work we consider functions like strcpy and strcat to be unsafe. Any kind of mistake in handing them pointers causes this problem.
Versions of strcpy and strcat exist, with slightly different names, which require an integer or size_t indicating their maximum valid size. strncat, for example, has the signature:
char * strncat( char *destination, const char *source, size_t num );
If, in your case, you had used strncat, providing 4 for the last parameter, it would not have crashed.
However, an alternative exists you may prefer to explore. You can simply use indexing, as in:
char destination[5]; // I like room for a zero terminator here
for(i=0; i<4; i++)
destination[i] = grid[0][i];
This does not handle the zero terminator, which you might append with:
destination[4] = 0;
Now, let's assume you wanted to continue, putting both words into a single output string. You might do:
char destination[10]; // I like room for a zero terminator here
int d=0;
for(r=0; r<2; ++r ) // I prefer the habit of prefix instead of postfix
{
for( i=0; i<4; ++i )
destination[d++] = grid[r][i];
destination[d++] = ' ';// append a space between words
}
Following whatever processing is required on what might be an ever larger declaration for destination, append a zero terminator with
destination[ d ] = 0;
strcpy copies strings, not chars. A string in C is a series of chars, followed by a \0. These are called "null-terminated" strings. So your calls to strcpy and strcat aren't giving them the right kind of parameters.
strcpy copies character after character until it hits a \0; it doesn't just copy the one char you're giving it a pointer to.
If you want to copy a character, can just assign it.
char destination[5];
for(i = 0; i < 4; i++)
destination[i] = grid[0][i];
destination[i] = '\0';
I want to copy all the characters in a char[] to another char[]. However, suppose there are is a '\0' then I want to treat that as a normal character--a literal if you will.
Therefore, when I printout the char[] with the format specifier %s, it should not stop in the middle.
e.g.
// chars copied to array x
char x[] = {'h','e','\0','l','l','o','\0'}
printf("%s\n",x); // prints 'he\0llo'
Is there a way to do this?
Use memcpy if you know how many characters you need to copy. If x is a real array as in your example, sizeof(x) will give you that amount, but if you pass x as a parameter to a function, sizeof will not work inside that function (it will just show the size of the pointer), so the basic rule is that your strings either should be NUL-terminated, or you should keep their size in a separate variable.
For printing, you can either print in the for loop as #alk suggests, or use fwrite to write any buffer (possibly with NULs) to stdout:
fwrite(x, sizeof(x), 1, stdout); /* sizeof will work only for a real array */
Wrong use of "%s". There is not a way to use printf("%s" to print an array with data after the first null character or '\0'.
char x[] = {'h','e','\0','l','l','o','\0'}
printf("%s\n",x); // This only prints "he"
printf("%s",... is for printing strings. x is a string only up to and including the first '\0'.
To "copy all the characters in a char[] to another char[].", use memcpy().
char x[] = {'h','e','\0','l','l','o','\0'}
char y[sizeof x];
memcpy(y, x, sizeof x);
Code could use "%c" to print everything, but what gets printed with '\0' varies amongst systems.
size_t i;
for (i=0; i< sizeof x; i++)
printf("%c", x[i]);
You need to print the array element wise, translating non-printable characters to whatever you want to see instead.
To print out he\0llo\0 do:
char x[] = {'h','e','\0','l','l','o','\0'};
for (size_t i = 0; i < sizeof(x); ++i)
{
if ('\0' == x[i])
{
printf("%s", "\\0");
}
else
{
printf("%c", x[i]);
}
}