explanation of strcat() output - c

this is one of the question from 295c
#include<stdio.h>
#include<string.h>
main()
{
char *a="kammo DJ";
const char *b="roomies!!";
char *c;
a=(char *)malloc(strlen(a) + strlen(b));
c=(char *)malloc(strlen(a) + strlen(b));
c=strcat(a,b);
printf("%s\n",a);
}
and the output is - roomies!!
but why the output should be concatenation of kammo DJ + roomies!!
also tell what is the value of c?

First, you should malloc the strlen(a) + strlen(b) + 1 because of the '\0' symbol. You already declared char * a = "kammo dj" so you can't allocate memory for that. When you did the malloc for char * a, it returned the location of the memory pool malloc created.
if you just do:
#include<stdio.h>
#include<string.h>
#include<malloc.h>
int main()
{
const char *a="kammo DJ";
const char *b="roomies!!";
char *c;
size_t len = strlen(a) + strlen(b) + 1;
c=(char *)malloc(len*sizeof(char));
strcpy(c,a);
strcat(c,b);
printf("%s\n",c);
// don't forget!
free(c);
return 0;
}
will output 'kammo DJroomies (no space between)

The poblem here is that when you do
a=(char *)malloc(strlen(a) + strlen(b));
It means a is no longer pointing to "kammo DJ". Instead it is pointing to freshly allocated memory contain arbitrary data.
It appears that the first byte of the data a is now pointing to happens to be 0, which effectively makes a the empty string. Which is why you are getting just roomies!! as your result. But that is just luck.
The code you really want is:
#include<stdio.h>
#include<string.h>
main()
{
const char *a="kammo DJ";
const char *b="roomies!!";
char *c;
c=(char *)malloc(strlen(a) + strlen(b) + 1);
strcpy(c,a);
strcat(c,b);
printf("%s\n",c);
}

a=(char *)malloc(strlen(a) + strlen(b));
You need room for the terminating null character. The size of a string is its length + one byte for the null character. Also a was declared to point at the "kammo DJ" string literal. After the malloc call you make the pointer points to something else.
c=strcat(a,b);
a is not a string and contains an indeterminate value after malloc.

Related

Confused between passing strings to a function (C)

Why this works:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char st[] = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
And this doesn't:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char*st = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
In first I initialized my string using:
char st[]="Hello"; (using array)
And in latter I used:
char*st="Hello"; (using pointer)
I'm kind of getting confused between these 2 initialization types, what's the key difference between declaring a string by using char st[]="Hello"; and by using char*st = "Hello";.
With char st[] = "Hello";, st[] is a modifiable array of characters. The call slice(st, 1, 6); takes the array st and converts to a pointer to the first element of the array. slice() then receives that pointer, a pointer to modifiable characters.
With char *st = "Hello";, st is a pointer that points to a string literal "Hello". With the call slice(st, 1, 6);, the function receives a copy of the pointer - a pointer to the string literal. Inside slice(), code st[i] = ... is attempting to modify a string literal, that is undefined behavior (UB). It might work, it might fail, it might work today and fail tomorrow - it is not defined.
Do not attempt to modify a string literal.
... passing strings to a function ...
In both cases, code does not pass a string to slice(), but a pointer to a string. Knowing that subtle distinction helps in understanding what is truly happening.
This is an artifact of old syntax in C:
char * s = "Hello world!";
is a non-const character pointer to const memory. It is still permitted by syntax, but the string is still not a mutable object. To be pedantic it should really be written as:
const char * s = "Hello world!";
In contrast:
char s[] = "Hello world!";
allocates a local (on the stack), mutable array and copies the string data to it (from wherever the non-mutable copy is stored in memory). Your function can then do as it likes to your local copy of the string.
The type char [] is different from the type char* (char* is a variable - int. but char[] is an array which is not a variable). However, an array name can be used as a pointer to the array.
So we can say that st[] is technically similar to *str .
the problem in the 2nd version of your code
If you have read-only strings then you can use const char* st = "hello"; or simply char* st = "hello"; . So the string is most probably be stored in a read-only memory location and you'll not be able to modify it.
However, if you want to be able to modify it, use the malloc function:
char *st= (char*) malloc(n*sizeof(char)); /* n-The initial size that you need */
// ...
free(st);
**So to allocate memory for st, count the characters ("hello"-strlen(st)=5) and add 1 for this terminating null character , and functions like scanf and strcpy will add the null character;
so the code becomes :
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char *st =malloc(6*sizeof(char)) ;
const char *cpy="hello";
strcpy(st, cpy); /* copies the string pointed by cpy (including the null character) to the st. */
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
you can fill your string also by a for loop or by scanf() .
in the case of a large allocation you must end your code with free(st);

Cant print a string in a struct

I'm trying to copy a string into a struct, but it doesn't display anything. Can you help me figure it out where the problem is?
typedef struct{
long tipo;
char *buffer;
}msg;
msg mess;
strcpy(mess.buffer,"hello");
printf("%s\n",mess.buffer);
Observing the strcpy declaration
char * strcpy ( char * destination, const char * source );
We notice that it copies the chars from source and store them in destination. But note that it's not specified the length of destination. So it may cause problems if the destination is:
Smaller than the source (Overflow)
Not allocated to some space in the memory (Segmentation Fault)
It's because strcpy function tries to copy char by char until it gets to the end of the 'string'. See how it should look like:
char *strcpy(char *destination , const char *source ){
char *saved = destination;
while (*source){ // while is not NULL
*destination++ = *source++; // Pointer operation
}
*destination = 0; // last position is set to 0 (which is NULL, end of string)
return saved;
}
So when you perform strcpy(mess.buffer,"hello") you can't actually find mess.buffer++ because there's no next memory block since you did not allocated sequential memory. Thus, Segmentation Fault happens.
Finally, you could do:
/* Note that "hello" occupies 6 char spaces: 'h', 'e', 'l', 'l', 'o', '\0' */
int mySize = 10;
mess.buffer = malloc(mySize * sizeof(char));
strcpy(mess.buffer, "hello") // 10 > 6 so OK
Either assign the string directly (note that you will no long be able to modify this string):
msg mess = {.buffer= "hello"};
or use malloc and memcpy function from libc which will perform a memory allocation and copy the bytes of your string to your char pointer for you:
if (!(mess.buffptr = malloc(sizeof(char) * (strlen(s) + 1))))
return 1;
memcpy(mess.buffptr, s, strlen(s));
But I think that what you are looking for is rather to use char buffer[128] instead of a char pointer, see the following example:
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct{
long tipo;
char buffer[128];
char *buffptr; // remove if not needed
} msg;
int main(){
char *s = "hello";
msg mess = {.buffer= "hello"};
mess.buffer[1] = 'a';
printf("'%s' assigned at struct initialization\n",mess.buffer);
(void)mess.buffer;
strcpy(mess.buffer,"hello");
printf("'%s' char array strcpy\n",mess.buffer);
int len = strlen(s) + 1; // to account for '\0'
if (!(mess.buffptr = malloc(sizeof(char) * len)))
return 1;
if (len <= sizeof(mess.buffer))
memcpy(mess.buffptr, s, len);
printf("'%s' char ptr malloced\n",mess.buffptr);
return 0;
}
You can read more about the different between a char pointer and a char array here

Trying to troubleshoot concatenating a string in C

I am trying to concatenate two strings together. I put two strings into two arrays and created a third array that is the size of the two strings. Then I use the for loop to print out one letter at a time.
The program gets to This before crashing. There are no error codes or debug messages in the IDE!!! How do I debug my program and what kind of mindset should I have if I have no obvious error messages to go off of when something like this happens?
#include <stdio.h>
#include <memory.h>
#include <malloc.h>
int pointerArrays() {
char strOne[] = {"This is the first string array."};
char strTwo[] = {"This is the second string array."};
char *px, *py, *pz;
px = strOne;
py = strTwo;
pz = (char *) malloc(1 + sizeof(px) + sizeof(py));
strcpy(pz, px);
strcpy(pz, py);
for (int i = 0; i < sizeof(pz); i++) {
printf("%c", pz[i]);
}
return 0;
}
int main(void) {
pointerArrays();
return 0;
}
There are two problems. First of all, this here doesn't work:
malloc(1 + sizeof(px) + sizeof(py));
sizeof(px) doesn't evaluate to the size of the string, it just evaluates to the size of a char*, which isn't what you intended. Instead, try something like this:
pz = (char *)malloc(strlen(strOne) + strlen(strTwo) + 1);
The second problem is that instead of concatenating the two strings, you're copying them over each other. The second call needs to be
strcat(pz, py);
Rather than strcpy again.
On a side note, when you print a string, instead of just looping through the array, you can also just use the %s format specifier:
printf("%s", pz);
Last but not least, don't forget to free the memory when you're done:
free(pz);
Insert another line to see what the argument to malloc() rceives:
printf ("malloc(%d)\n", 1 + sizeof(px) + sizeof(py));
I bet you can figure it out from there.
Just a sidenote (not the reason of your crash): you are copying to the same location twice:
strcpy(pz, px);
strcpy(pz, py);
should be
strcpy(pz, px);
strcpy(pz + strlen(px), py);
not fixing it would cause y to right OVER x
But the main issue is using sizeof instead of strlen. sizeof will return the pointer's size (4 or 8 typically), while strlen will actually return the length of the string (which is what you expected)
using sizeof is very dangerous and will fail in most real life usage cases.
it is enough to change
char strOne[] = "This is the first string array.";
char strTwo[] = "This is the second string array.";
to
char strOne[64] = "This is the first string array.";
char strTwo[64] = "This is the second string array.";
or
char *strOne = "This is the first string array.";
char *strTwo = "This is the second string array.";
and the result of your function will be far from the expected.
Always use strlen to get the string length.
Here you have much more universal and safer solution:
char *concatenate(const char *str1, const char *str2)
{
size_t str1len = strlen(str1), str2len = strlen(str2);
char *res = malloc(str1len + str2len + 1);
if(res)
{
strcpy(res, str1);
strcpy(res + str1len, str2);
}
return res;
}

Shifting a char array prior to adding to it

I want to insert characters into the middle of a char array in C, but first I want to shift it to the right each time prior to adding a char so that I don't lose what's already in the char array (called input) by overwriting.
I assume you are terminating the array with a null char since you are using strlen. In that case, I'm pretty sure the first iteration of your for loop will overwrite the null character with the preceding char, and you don't seem to replace it. Try running
for( k = strlen(input) + 1; k > place42; k--)...
This should replace your null character so that your array is properly terminated. Of course you should also be sure you are not overflowing your array and writing on memory that doesn't belong to you.
Why not a write a generic insert routine using the standard C string functions? Something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// insert "ins" into "src" at location "at"
char *insert(char *src, char *ins, int at) {
char dst[strlen(src) + strlen(ins) + 1];
strncpy(dst, src, at);
strcpy(dst + at, ins);
strcpy(dst + at + strlen(ins), src + at);
return strdup(dst);
//return strcpy(src, dst); // you could return this if you know src is long enough
}
int main(void) {
char *src = "abcdef";
char *ins = "123";
printf("%s\n", insert(src, ins, 3));
return 0;
}
prints
abc123def

Manipulating dynamic arrays in C

I am trying to solve StringMerge (PP0504B) problem from SPOJ (PL). Basically the problem is to write a function string_merge(char *a, char *b) that returns a pointer to an char array with string created from char arrays with subsequent chars chosen alternately (length of the array is the length of the shorter array provided as an argument).
The program I've created works well with test cases but it fails when I post it to SPOJ's judge. I'm posting my code here, as I believe it the problem is related to memory allocation (I'm still learning this part of C) - could you take a look at my code?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define T_SIZE 1001
char* string_merge(char *a, char *b);
char* string_merge(char *a, char *b) {
int alen = strlen(a); int blen = strlen(b);
int len = (alen <= blen) ? alen : blen;
int i,j;
char *new_array = malloc (sizeof (char) * (len));
new_array[len] = '\0';
for(j=0,i=0;i<len;i++) {
new_array[j++] = a[i];
new_array[j++] = b[i];
}
return new_array;
}
int main() {
int n,c; scanf("%d", &n);
char word_a[T_SIZE];
char word_b[T_SIZE];
while(n--) {
scanf("%s %s", word_a, word_b);
char *x = string_merge(word_a, word_b);
printf("%s",x);
printf("\n");
memset(word_a, 0, T_SIZE);
memset(word_b, 0, T_SIZE);
memset(x,0,T_SIZE);
}
return 0;
}
Note: I'm compiling it with -std=c99 flag.
Off-by-one.
char *new_array = malloc (sizeof (char) * (len));
new_array[len] = '\0';
You're writing past the bounds of new_array. You must allocate space for len + 1 bytes:
char *new_array = malloc(len + 1);
Also, sizeof(char) is always 1, so spelling it out is superfluous, so are the parenthesis around len.
Woot, further errors!
So then you keep going and increment j twice within each iteration of the for loop. So essentially you end up writing (approximately) twice as many characters as you allocated space for.
Also, you're leaking memory by not free()ing the return value of string_merge() after use.
Furthermore, I don't see what the memsets are for, also I suggest you use fgets() and strtok_r() for getting the two words instead of scanf() (which doesn't do what you think it does).
char *new_array = malloc (sizeof (char) * (len*2 + 1));
new_array[len*2] = '\0';

Resources