Why strcat doesn't work with pointer in C? - c

When I execute this with a normal array it's working but with a pointer it doesn't.
#include <stdio.h>
#include <string.h>
int main()
{
char source[]="Agdhefhe";
char *accum = "";
for(int i=0;i<=sizeof(*source)/sizeof(char);i++)
{
for(int j=0; j<i; j++)
strcat(accum,source);
}
printf("%s",accum);
return 0;
}

The pointer accum points to the constant initialiser which has length 1. The result of both writing to the initialiser's data area and overrunning the allocated space is undefined.
accum must point to a writable region with sufficient space allocated to accommodate the final string.

To get it right you need to allocation enough space for the destination to write to.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char source[] = "Agdhefhe";
size_t sz = 360;
char *accum = (char *) malloc(sz + 1);
*accum = '\0'; // needed for first strcat call
for (int i = 0; i <= sizeof(*source) / sizeof(char); i++)
for (int j = 0; j < i; j++)
strncat(accum, source, sz); // strncat used to not write too much
printf("%s", accum);
free(accum);
return 0;
}
This program writes Agdhefhe but can be simplified to
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char const source[] = "Agdhefhe";
size_t sz = 360;
char *accum = (char *) malloc(sz + 1);
*accum = '\0'; // needed for first strcat call
strncat(accum, source, sz);
printf("%s", accum);
free(accum);
return 0;
}
But if you wanted to duplicate the string a number of times you write:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char const source[] = "Agdhefhe";
size_t sz = 360;
char *accum = (char *) malloc(sz + 1);
*accum = '\0'; // needed for first strcat call
for (int i = 0; i <= sizeof(source) / sizeof(char); i++) // the change is here
for (int j = 0; j < i; j++)
strncat(accum, source, sz);
printf("%s", accum);
free(accum);
return 0;
}
This writes AgdhefheAgdhefheAgdhefheAgdhefhe...Agdhefhe (360 characters).

Related

Segmentation fault and 'free' called on a pointer to an unallocated object

I am currently writing a program to simply reverse a string in C. However, when I try to copy the contents of the temp string I made into the original string, I get a segmentation fault. Also, when I try to free the memory I allocated for my test string I get a warning which says " 'free' called on a pointer to an unallocated object "
Here is my code:
void reverseString(char* str, size_t size) {
char *temp = (char*) malloc(sizeof(str) + 1);
int j = size;
for (int i = 0; i < size; i++) {
temp[i] = str[j];
j--;
}
for (int i = 0; i < size; i++) {
str[i] = temp[i];
}
free(temp);
return;
}
int main() {
char* result = (char*)(malloc(sizeof(char) * 10));
result = "Forty-two";
reverseString(result, strlen(result));
printf("%s", result);
free(result);
result = NULL;
return 0;
}
On the second line, you should be using strlen instead of sizeof, because otherwise you will be allocating space for a character pointer and you need more than that.
sizeof(str) returns size of pointer not length of the literal.
Array index starts from 0. That's why j should starts with (size - 1)
You are allocating memory from heap, use memset before do something.
#bereal already says, if you want to understand more, please check this out :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char* result = (char*)(malloc(sizeof(char) * 10));
memset(result, 0, 10);
printf("Addr of result var : %p \n", result);
result = "Re-assign";
printf("Addr of result var : %p \n", result);
return 0;
}
Maybe my solution gives an idea for you
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void reverseString(char** str, size_t size) {
char *temp = (char*) malloc(size + 1);
memset(temp, 0, size + 1);
int j = size - 1;
for (int i = 0; i < size; i++) {
temp[i] = str[0][j];
j--;
}
//Change addr of holding str
*str = temp;
return;
}
int main() {
char* result = "Forty-two";
reverseString(&result, strlen(result));
printf("%s", result);
//result holds same addr with temp
free(result);
return 0;
}
But there are ways to solve this question more accurately.

Create function which sorts 2 given sorted strings

Given two sorted strings, I need to merge these strings to one string, and make it sorted.
sort by the ASCII value. for example:
acdty, berz => abcdertyz
My code:
#include <stdio.h>
#include <stdlib.h>
char* PairSortedArrays(char a[], char b[]) {
char* c = (char*)malloc((sizeof(a) + sizeof(b)) * sizeof(char));
int i, aPos = 0, bPos = 0;
for (i = 0; i < sizeof(*c); i++) {
if ((int)(a[aPos]) <= (int)(b[bPos])) {
c[i] = a[aPos];
aPos++;
}
else {
c[i] = b[bPos];
bPos++;
}
}
return c;
}
int main()
{
printf("%s", PairSortedArrays("acdty", "berz"));
return 0;
}
The first problem is with sizeof(a). if I code: printf("%d", sizeof(a)); it prints 8, while I expect it to print 5.
The expression i < sizeof(*c) controling the for loop is the main culprit. The corrected version of your program could be: (I edited the code a bit)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* PairSortedArrays(const char a[], const char b[])
{
size_t i;
const size_t total_len = strlen(a)+strlen(b);
char *c = malloc(total_len + 1);
size_t aPos = 0, bPos = 0;
for (i = 0; i < total_len; i++) {
if (a[aPos] == '\0') {
strcpy(c + i, b + bPos);
break;
}
if (b[bPos] == '\0') {
strcpy(c + i, a + aPos);
break;
}
c[i] = a[aPos] < b[bPos] ? a[aPos++] : b[bPos++];
}
return c;
}
int main()
{
printf("%s\n", PairSortedArrays("acdty", "berz"));
printf("%s\n", PairSortedArrays("az", "ks"));
return 0;
}
The return value of malloc must be checked against NULL in a real program. Also there is a memory leak (easy to fix).
When working with strings in C, you will want to be using strlen() to see how long they are, not sizeof (which merely tells you what the size of a pointer is).
Also note that sizeof(char) is 1 by definition, so there's no need to say "* sizeof(char)" in your malloc
sizeof(a) will return the size of a pointer in this case which will be 8 bytes if you compile for 64 architecture.
you have to either pass the size of each string or loop the string characters until you reach the '\0' if the string is null-terminated.
You should consider using qsort:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare_chars(const void *p1, const void *p2)
{
return *(const char *)p1 - *(const char *)p2;
}
char *PairSortedArrays(char *a, char *b)
{
char *c = malloc(strlen(a)+strlen(b)+1);
strcpy(c, a);
strcat(c, b);
qsort(c, strlen(c), sizeof(char), compare_chars);
return c;
}
int main()
{
printf("%s", PairSortedArrays("acdty", "berz"));
return 0;
}

Converting lowercase letters to uppercase

I have a program to reverse a string and convert it to uppercase. If I write helloworld!, the output must be !DLROWOLLEH. But if I write hello world! the output is !DLRO. Could you tell me where the possible problem is?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char * reverse(const char * text)
{
if (text==NULL)
return NULL;
int length = strlen(text);
char * reversed_string = malloc(length+1);
for(int i = 0; i < length/2; ++i)
{
reversed_string[i] = text[(length-1) - i];
reversed_string[(length-1) - i] = text[i];
}
reversed_string[length] = '\0';
//upper(reversed_string);
return reversed_string;
}
void upper(char *str1)
{
while(*str1!='\0')
{
if(*str1>96&&*str1<123)
*str1=*str1-32;
str1++;
}
}
int main(int argc, char * argv[])
{
char p[256];
fgets(p, sizeof(p), stdin);
char * rev_str = reverse(p);
upper(rev_str);
printf("%s\n", rev_str);
rev_str = 0;
return 0;
}
The problem is here
for(int i = 0; i < length/2; ++i)
It length is an odd number (like 11 in your example), this will implicitly round down, and as a consequence, you never write to the middle element in the string. Un your case, this happened to be 0, but that is not guaranteed to be so, so any character might have appeared there, instead of terminating the string early.
The easiest fix would be changing that to (length+1)/2, but that will have the effect that you write the middle element twice.
Actually, I think it is much easier if you just reverse the string just by iterating over it in one direction instead of from both.
I've modified your code and it works as expected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char * reverse(const char * text)
{
if (text==NULL)
return NULL;
unsigned long length = strlen(text);
char * reversed_string = malloc(length+1);
for(int i = 0; i < length; ++i)
{
reversed_string[i] = text[(length-1) - i];
//reversed_string[(length-1) - i] = text[i];
}
reversed_string[length] = '\0';
//upper(reversed_string);
return reversed_string;
}
void upper(char *str1)
{
while(*str1!='\0')
{
if(*str1>96&&*str1<123)
*str1=*str1-32;
str1++;
}
}
int main(int argc, char * argv[])
{
char p[256];
fgets(p, sizeof(p), stdin);
char * rev_str = reverse(p);
printf("%s\n", rev_str);
upper(rev_str);
printf("%s\n", rev_str);
rev_str = 0;
return 0;
}

Splint: "Value strings[] used before definition" with dynamic array

I'm using a dynamic array of strings in C:
char** strings;
I initialize it:
int max = 10;
strings = malloc(sizeof(char*) * max);
And copy a couple of dummy strings:
char* str = "dummy";
for (int i = 0; i < max; i++) {
strings[i] = malloc(strlen(str) + 1);
strncpy(strings[i], str, strlen(str) + 1);
}
Yet when I try to print this:
for (int i = 0; i < max; i++)
printf("array = %s", strings[i])
I get this error from Splint:
Value strings[] used before definition
An rvalue is used that may not be initialized to a value on some execution
path. (Use -usedef to inhibit warning)
Checking for NULL like this will not help:
for (int i = 0; i < max; i++)
if (strings[i] != NULL)
printf("array = %s", strings[i])
since strings[i] is still used "before definition".
Any ideas on how to solve this?
Edit: Will try this with a linked list instead, I think.
Also, complete code listing:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char** strings;
int i;
int max = 10;
char* str = "hello";
// Dynamic array with size max
strings = malloc(sizeof(char*) * max);
// Abort if NULL
if (strings == NULL)
return (-1);
// Define strings
for (i = 0; i < max; i++)
{
strings[i] = malloc(strlen(str) + 1);
// Abort if NULL
if (strings[i] == NULL)
{
// Undetected memory leak here!
free(strings);
return (-1);
}
strncpy(strings[i], str, strlen(str) + 1);
}
// Print strings
for (i = 0; i < max; i++)
{
if (strings[i] != NULL)
printf("string[%d] = %s\n", i, strings[i]);
}
// Free strings
for (i = 0; i < max; i++)
{
if (strings[i] != NULL)
free(strings[i]);
}
free(strings);
return 0;
}
I do not have Splint on my machine, so i cannot test with it, just an another way to your task:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int i, len, max;
char* str = "hello";
len = strlen(str) + 1;
max = 10;
char strings[max][len];
for (i = 0; i < max; i++) {
strcpy(strings[i], str);
}
for (i = 0; i < max; i++) {
printf("string[%d] = %s\n", i, strings[i]);
}
return 0;
}
Avoid creating non-continuous memory it would be better approach if you allocate memory in single malloc call.
Memory can be freed in single free call instead of multiple free call
max_rows * sizeof(char) will allocate 2 * 1
((strlen(str) * N) + 1) will allocate memory for every N element.
Here is my approch
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
size_t max_rows = 2;
char* str = "dummpy";
char* vec_s = (char *) malloc( max_rows * sizeof(char) * ((strlen(str) * max_rows) + 1));
for (int i = 0; i < max_rows; i++){
strcpy((vec_s + i), str);
printf("vec_s[%d]=%s\n", i, (vec_s + i));
}
free(vec_s);
return 0;
}

Multiply strings in C

I wrote a simple program to multiply a string a defined times.
But, it doesn't really work, and don't know why...
It's so simple that I don't know what the problem could be...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *product(char *str, int k);
int main()
{
char strg[1000];
char *prod;
int mult;
scanf("%s", strg);
scanf("%d", mult);
prod = product(strg, mult);
printf("%s\n", prod);
return EXIT_SUCCESS;
}
char *product(char *str, int k)
{
int i, j;
int len = strlen(str);
char *res = (char *) malloc(sizeof(char) * (len * k + 1));
for (i = 0, j = 0; i < (len * k); i++, j++)
{
if (j == len) j = 0;
res[i] = str[j];
}
res[++i] = '\0';
return res;
}
Anyone who can help me to figure out where's the problem? :D
At the end of the loop, i is already the index of the position for the terminator.
Just do
res[i] = 0;

Resources