Combine characters from a two dimensional array into a string in C - c

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';

Related

string gets filled with garbage

i got a string and a scanf that reads from input until it finds a *, which is the character i picked for the end of the text. After the * all the remaining cells get filled with random characters.
I know that a string after the \0 character if not filled completly until the last cell will fill all the remaining empty ones with \0, why is this not the case and how can i make it so that after the last letter given in input all the remaining cells are the same value?
char string1 [100];
scanf("%[^*]s", string1);
for (int i = 0; i < 100; ++i) {
printf("\n %d=%d",i,string1[i]);
}
if i try to input something like hello*, here's the output:
0=104
1=101
2=108
3=108
4=111
5=0
6=0
7=0
8=92
9=0
10=68
You have an uninitialized array:
char string1 [100];
that has indeterminate values. You could initialize the array like
char string1 [100] = { 0 };
or
char string1 [100] = "";
In this call
scanf("%[^*]s", string1);
you need to remove the trailing character s, because %[] and %s are distinct format specifiers. There is no %[]s format specifier. It should look like this:
scanf("%[^*]", string1);
The array contains a string terminated by the zero character '\0'.
So to output the string you should write for example
for ( int i = 0; string1[i] != '\0'; ++i) {
printf( "%c", string1[i] ); // or putchar( string1[i] );
putchar( '\n' );
or like
for ( int i = 0; string1[i] != '\0'; ++i) {
printf("\n %d=%c",i,string1[i]);
putchar( '\n' );
or just
puts( string1 );
As for your statement
printf("\n %d=%d",i,string1[i]);
then it outputs each character (including non-initialized characters) as integers due to using the conversion specifier d instead of c. That is the function outputs internal ASCII representations of characters.
I know that a string after the \0 character if not filled completly
until the last cell will fill all the remaining empty ones with \0
No, that's not true.
It couldn't be true: there is no length to a string. No where neither the compiler nor any function can even know what is the size of the string. Only you do. So, no, string don't autofill with '\0'
Keep in minds that there aren't any string types in C. Just pointer to chars (sometimes those pointers are constant pointers to an array, but still, they are just pointers. We know where they start, but there is no way (other than deciding it and being consistent while coding) to know where they stop.
Sure, most of the time, there is an obvious answer, that make obvious for any reader of the code what is the size of the allocated memory.
For example, when you code
char string1[20];
sprintf(string1, "hello");
it is quite obvious for a reader of that code that the allocated memory is 20 bytes. So you may think that the compiler should know, when sprinting in it of sscaning to it, that it should fill the unused part of the 20 bytes with 0. But, first of all, the compiler is not there anymore when you will sscanf or sprintf. That occurs at runtime, and compiler is at compilation time. At run time, there is not trace of that 20.
Plus, it can be more complicated than that
void fillString(char *p){
sprintf(p, "hello");
}
int main(){
char string1[20];
string1[0]='O';
string1[1]='t';
fillString(&(string1[2]));
}
How in this case does sprintf is supposed to know that it must fill 18 bytes with the string then '\0'?
And that is for normal usage. I haven't started yet with convoluted but legal usages. Such as using char buffer[1000]; as an array of 50 length-20 strings (buffer, buffer+20, buffer+40, ...) or things like
union {
char str[40];
struct {
char substr1[20];
char substr2[20];
} s;
}
So, no, strings are not filled up with '\0'. That is not the case. It is not the habit in C to have implicit thing happening under the hood. And that could not be the case, even if we wanted to.
Your "star-terminated string" behaves exactly as a "null-terminated string" does. Sometimes the rest of the allocated memory is full of 0, sometimes it is not. The scanf won't touch anything else that what is strictly needed. The rest of the allocated memory remains untouched. If that memory happened to be full of '\0' before the call to scanf, then it remains so. Otherwise not. Which leads me to my last remark: you seem to believe that it is scanf that fills the memory with non-null chars. It is not. Those chars were already there before. If you had the feeling that some other methods fill the rest of memory with '\0', that was just an impression (a natural one, since most of the time, newly allocated memory are 0. Not because a rule says so. But because that is the most frequent byte to be found in random area of memory. That is why uninitialized variables bugs are so painful: they occur only from times to times, because very often uninitialized variables are 0, just by chance, but still they are)
The easiest way to create a zeroed array is to use calloc.
Try replacing
char string1 [100];
with
char *string1=calloc(1,100);

C - How can I concatenate an array of strings into a buffer?

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

Strange characters at the end of string

I want to fill a string with '_' so I have
while (i < length) {
myWord[i] = 95;
i++;
}
length is const int typed by user. but when i type printf("%s",myWord); it's output is '____#S' or '____#' or sometimes it's output is good.
Where is a problem? Thank you :)
A String must end with a \0 char
while (i < length) {
myWord[i] = 95;
i++;
}
myWorkd[i] = 0;
Allowing the user to enter in the length of the string is prone to error. What if the user enters in 99999 and the length is actually 10? Boom. Undefined behavior.
If you had used a string literal, it would have been automatically null-terminated by default. char arrays are not automatically null-terminated.
What happens if a string that isn't null-terminated gets passed to
strlen()? Undefined Behavior. strlen(), when given such a beast,
will keep searching memory until it a) finds a null character; or b)
hits an address that causes a memory protection fault of some sort (or
worse). strlen(), at least, is read-only; so it won't corrupt data.
http://c2.com/cgi/wiki?NonNullTerminatedString
Since you don't know the size of the array, a safer alternative would be to figure it out yourself:
int elements_in_x = sizeof(x) / sizeof(x[0]);
For the specific case of char, since sizeof(char) == 1, sizeof(x) will yield the same result.
If you only have a pointer to an array, then there's no way to find the number of elements in the pointed-to array. You have to keep track of that yourself. For example, given:
char x[10];
char* pointer_to_x = x;
there is no way to tell from just pointer_to_x that it points to an array of 10 elements. You have to keep track of that information yourself.
Most probably you forget to terminate your string with NUL (\0) character.

Concatenating multiple strings?

I am processing an input string, which consists of a process name, followed by an arbitrary amount of arguments.
I need the process name , along with all of the arguments, in one string.
I thought I could use strcat in a loop, so that it cycles through all of the args and each time appends the arg to the string, but I am having problems with getting a string that in empty to begin the loop.
Can anyone help me out with some basic code?
Thanks.
EDIT:
I'm posting my code for clarity. Mike's post is closest to what I have now:
char * temp;
strcpy(temp,"");
for (i = 4; i < argc-1; i++) // last arg is null, so we need argc-1
{
strcat(temp,argv[i]);
strcat(temp," ");
}
ignore the 4 in my for loop for the moment (magic number, i know.)
I am getting a segfault with this code. Is it because of my string assignment? I assume that is the case and hence I asked the question of how i could combine the strings.
Let's say your input strings are in an array of char pointers, suggestively called argv, of length argc.
We first need to determine how much space is needed for the output:
int length = 0;
for (int i = 0; i < argc; ++i)
length += strlen(argv[i]);
Then we allocate it, adding an extra char for the '\0' terminator:
char *output = (char*)malloc(length + 1);
Finally, the concatenation:
char *dest = output;
for (int i = 0; i < argc; ++i) {
char *src = argv[i];
while (*src)
*dest++ = *src++;
}
*dest = '\0';
Note that I don't use strcat here. Reason is that this sets us up for a Schlemiel the Painter's algorithm: for each iteration, the entire output string would be scanned to find its end, resulting in quadratic running time.
Don't forget to free the output string when you're done:
free(output);
I'm a bit tired so I may be overlooking something here. A better solution, using standard library functions, is welcome. It would be convenient if strcat returned a pointer to the terminator byte in dest, but alas.
You want an empty C string? Is this what you are looking for: char p[] = "";?
UPDATE
After you posted some code it is clear that you have forgotten to allocate the buffer temp. Simply run around the arguments first, counting up the length required (using strlen), and then allocate temp. Don't forget space for the zero terminator!
You could provide the "arbitrary amount of arguments" as one argument, ie an array/list, then do this pseudocode:
str = "";
i = 0;
while i < length of input
{
str = strcat ( str , input[i]);
i++;
}
#include<stdio.h>
#include<stdarg.h>
int main(int argc, char** argv) {
// the main parameters are the same situation you described
// calling this program with main.exe asdf 123 fdsa, the program prints out: asdf123fdsa
int lengths[argc];
int sum =0;
int i;
for(i=1; i<argc; i++) { // starting with 1 because first arg is program-path
int len = strlen(argv[i]);
lengths[i] = len;
sum+=len;
}
char* all = malloc(sum+1);
char* writer = all;
for(i=1; i<argc; i++) {
memcpy(writer, argv[i], lengths[i]);
writer+=lengths[i];
}
*writer = '\0';
printf("%s\n", all);
system("pause");
return 0;
}
A string in C is represented by an array of characters that is terminated by an "null" character, '\0' which has the value 0. This lets all string functions know where the end of a string is. Here's an exploration of different ways to declare an empty string, and what they mean.
The usual way of getting an empty string would be
char* emptyString = "";
However, emptyString now points to a string literal, which cannot be modified. If you then want to concatenate to an empty string in your loop, you have to declare it as an array when you initialize.
char buffer[] = "";
This gives you an array of size one. I.e. buffer[0] is 0. But you want an array to concatenate to- it has to be large enough to accomodate the strings. So if you have a string buffer of certain size, you can initialize it to be empty like so:
char buffer[256] = "";
The string at buffer is now "an empty string". What it contains, is buffer[0] is 0 and the rest of the entries of the buffer might be garbage, but those will be filled once you concatenate your other strings.
Unfortunately, the problem with C, is you can never have an "infinite" string, where you are safe to keep concatenating to, you have to know it's definite size from the start. If your array of arguments are also strings, you can find their length using strlen. This gives you the length of a string, without the null character. Once you know the lengths of all your sub-strings, you will now know how long your final buffer will be.
int totalSize; // assume this holds the size of your final concatenated string
// Allocate enough memory for the string. the +1 is for the null terminator
char* buffer = malloc(sizeof(char) * (totalSize + 1));
buffer[0] = 0; // The string is now seen as empty.
After this, you are free to concatenate your strings using strcat.

Copying arrays in C

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);

Resources