Problems with implementation of concatenation function in C - c

I am still new to pointers in C and have been trying to make string functions. This one is supposed to concatenate two strings, but when I try to run it, it crashes.
void concatenate (char *a, char *b, int size_a, int size_b) {
char *c, *d, *e;
c = a;
d = b;
int i, j, k;
int l = 1;
for(i = 0; i<size_a; i++) {
*(e+i) = *(c+i);
}
for (j = size_a; j<size_a+size_b; j++) {
*(e+j) = *(d+(j-(j-l)));
l++;
}
for (k = 0; k< size_a+size_b; k++){
printf("%c",*(e+k));
}
}
What am I doing wrong?

You are trying to access the memory where uninitialized pointer e points to, which leads to undefined behavior.
Your function should look like this:
char* concatenate (const char *a, const char *b, int size_a, int size_b) {
// create new string:
char* newStr = malloc (size_a + size_b + 1);
int i, j;
// copy first string into it:
for (i = 0; i<size_a; i++)
newStr[i] = a[i];
// copy second string into it:
for (j = 0; j < size_b; j++)
newStr[i + j] = b[j];
newStr[i + j] = '\0';
return newStr;
}
Note that function doesn't change strings that are passed to it, thus they can be passed as const. The size_a and size_b are expected to be equal to strlen(a) and strlen(b), which also means that in case you always pass null-terminated strings into this function, you can calculate their length on your own within its body (so you can get rid of last 2 arguments).

e is an uninitialized pointer, which means it is pointing to some random place in memory. When you start writing to it as if it were a pointer to a character array, your program will crash (or worse, change some state mysteriously causing unspecified behavior later on).

Your code seems obfuscated for no reason. The problem is that you're assigning to e, which is uninitialized. The following is, pretty much, your code in a more readable form and with e allocated. I haven't tested it, though.
void concatenate (char *c, char *d) {
char *e;
e = calloc(strlen(c) + strlen(d) + 1, sizeof(char));
int i, j;
int l = 1;
for(i = 0; c[i]; i++) {
e[i] = c[i];
}
l = i;
for (j = 0; d[j]; j++) {
e[l + j] = d[j];
}
e[l + j] = '\0';
printf("%s", e);
free(e);
}

Related

Free array returned from function

apologies if this has appeared elsewhere, I've not been able to find a clear answer.
I've been using Ed S's answer, Option 1 (linked below) to allocate memory, populate the array, then return it back to the caller.
He recommends freeing the memory after you've finished with it, however when I added the free() line, I get a core dump.
I've had a poke around with GDB, but my skills probably aren't what the need to be.
Thanks in advance for any help you can give.
Link to answer: Returning an array using C
Code:
#include <stdio.h>
#include <stdlib.h>
char * createArray();
int main(int argc, char *argv[]){
printf("Creating Array...\n");
// pointer to an int
char *p;
// size of the array
int i,j;
// width of array
int width = 7;
// height of array
int height = 5;
// get an array from the function
p = createArray(width, height);
// check if p was created properly
if (p){
// print out the array
for (i = 0; i < width; ++i){
for (j = 0; j < height; ++j){
printf("[%c] ", *(p + (i * width) + j));
}
printf("\n");
}
// here's where it hits the fan
free(p);
}
return 0;
}
char * createArray(int w, int h){
// allocate some memory for the array
char *r = malloc(w * h * sizeof(char));
// check if the memory allocation was successful
if(!r){
return NULL;
}
int i, j;
int count = 0;
for (i = 0; i < w; ++i){
for (j = 0; j < h; ++j){
*(r + (i * w) + j) = 'X';
++count;
}
}
return r;
}
With this
char *r = malloc(w * h * sizeof(char));
You allocate w * h (7 * 5 = 35 bytes) of memory. But
*(r + (i * w) + j) = 'X';
can access well beyond the 35 bytes you have allocated (you'll see if you test the possible values for i * w + j in the loop), resulting in undefined behaviour.
This possibly overwrites the malloc's internal data structures and thus you happen to get core dump when you free().
You made a mistake on these lines
*(r + (i * w) + j) = 'X';
and
printf("[%c] ", *(p + (i * width) + j));
To keep inside the boundaries of your "2D" array -it's one dimensional but you are working around it like a compiler would-it should be i * length in there:
*(r + (i * h) + j) = 'X';`
and
printf("[%c] ", *(p + (i * height) + j)); `
If you use this, you should be able to stay within the boundaries without making a mess.

Function Parameter Changes in C

i've tried searching for the answer/ looking at the C library for pointers, but wasn't sure on the right solution. My question concerns changing the parameters of a function. I've been reading on pointers/functions, and from my understanding, if a function takes in (int x1), then when the function is done with x1, x1 outside the function remains untouched. However, if you pass in a int *x1, then it is changed.
I've been experimenting with it, and i've tried using this with a sort method...
void sorting(int *arr, int size) {
int *i, *j, temp;
int *len = arr + size - 1;
for(i = arr; i < len; i++) {
for(j = i + 1; j <= len; j++) {
if(*j < *i) {
temp = *i;
*i = *j;
*j = temp;
}
}
}
int k;
for(k = 0; k < size; k++) {
printf("k: %d, arr[k]: %d \n", k, *(arr + k));
}
}
What this would print is a fully sorted list. However, in my main function, if I called this...
int main() {
int temp[5] = {0, 2, 1, 3, 1};
int *p = &temp[5];
sorting(pa, 5);
print the values of pa...
}
Then the list remains unsorted if printing out the values of pa.
If this question has already been solved, could someone please link the question, and i'll delete the post.
You're accessing the array out of bounds here:
int *p = &temp[5];
The valid indices are [0, 5). Presumably you want a pointer to the first element:
int *p = &temp[0];
But note that you can pass an array to a function that expects a pointer. In this case the array decays to a pointer to the first element:
sorting(temp, 5);

C Allocating array of 500 and more longs

So.. I have something like this. It is supposed to create arrays with 10, 20, 50 100 .. up to 5000 random numbers that then sorts with Insertion Sort and prints out how many comparisions and swaps were done .. However, I am getting a runtime exception when I reach 200 numbers large array .. "Access violation writing location 0x00B60000." .. Sometimes I don't even reach 200 and stop right after 10 numbers. I have literally no idea.
long *arrayIn;
int *swap_count = (int*)malloc(sizeof(int)), *compare_count = (int*)malloc(sizeof(int));
compare_count = 0;
swap_count = 0;
int i, j;
for (j = 10; j <= 1000; j*=10) {
for (i = 1; i <= 5; i++){
if (i == 1 || i == 2 || i == 5) {
int n = i * j;
arrayIn = malloc(sizeof(long)*n);
fill_array(&arrayIn, n);
InsertionSort(&arrayIn, n, &swap_count, &compare_count);
print_array(&arrayIn, n, &swap_count, &compare_count);
compare_count = 0;
swap_count = 0;
free(arrayIn);
}
}
}
EDIT: ok with this free(arrayIn); I get this " Stack cookie instrumentation code detected a stack-based buffer overrun." and I get nowhere. However without it it's "just" "Access violation writing location 0x00780000." but i get up to 200numbers eventually
void fill_array(int *arr, int n) {
int i;
for (i = 0; i < n; i++) {
arr[i] = (RAND_MAX + 1)*rand() + rand();
}
}
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count) {
int i, j, t;
for (j = 0; j < n; j++) {
(*compare_count)++;
t = arr[j];
i = j - 1;
*swap_count = *swap_count + 2;
while (i >= 0 && arr[i]>t) { //tady chybí compare_count inkrementace
*compare_count = *compare_count + 2;
arr[i + 1] = arr[i];
(*swap_count)++;
i--;
(*swap_count)++;
}
arr[i + 1] = t;
(*swap_count)++;
}
}
I am sure your compiler told you what was wrong.
You are passing a long** to a function that expects a int* at the line
fill_array(&arrayIn, n);
function prototype is
void fill_array(int *arr, int n)
Same problem with the other function. From there, anything can happen.
Always, ALWAYS heed the warnings your compiler gives you.
MAJOR EDIT
First - yes, the name of an array is already a pointer.
Second - declare a function prototype at the start of your code; then the compiler will throw you helpful messages which will help you catch these
Third - if you want to pass the address of a simple variable to a function, there is no need for a malloc; just use the address of the variable.
Fourth - the rand() function returns an integer between 0 and RAND_MAX. The code
a[i] = (RAND_MAX + 1) * rand() + rand();
is a roundabout way of getting
a[i] = rand();
since (RAND_MAX + 1) will overflow and give you zero... If you actually wanted to be able to get a "really big" random number, you would have to do the following:
1) make sure a is a long * (with the correct prototypes etc)
2) convert the numbers before adding / multiplying:
a[i] = (RAND_MAX + 1L) * rand() + rand();
might do it - or maybe you need to do some more casting to (long); I can never remember my order of precedence so I usually would do
a[i] = ((long)(RAND_MAX) + 1L) * (long)rand() + (long)rand();
to be 100% sure.
Putting these and other lessons together, here is an edited version of your code that compiles and runs (I did have to "invent" a print_array) - I have written comments where the code needed changing to work. The last point above (making long random numbers) was not taken into account in this code yet.
#include <stdio.h>
#include <stdlib.h>
// include prototypes - it helps the compiler flag errors:
void fill_array(int *arr, int n);
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count);
void print_array(int *arr, int n, int *swap_count, int *compare_count);
int main(void) {
// change data type to match function
int *arrayIn;
// instead of mallocing, use a fixed location:
int swap_count, compare_count;
// often a good idea to give your pointers a _p name:
int *swap_count_p = &swap_count;
int *compare_count_p = &compare_count;
// the pointer must not be set to zero: it's the CONTENTs that you set to zero
*compare_count_p = 0;
*swap_count_p = 0;
int i, j;
for (j = 10; j <= 1000; j*=10) {
for (i = 1; i <= 5; i++){
if (i == 1 || i == 2 || i == 5) {
int n = i * j;
arrayIn = malloc(sizeof(long)*n);
fill_array(arrayIn, n);
InsertionSort(arrayIn, n, swap_count_p, compare_count_p);
print_array(arrayIn, n, swap_count_p, compare_count_p);
swap_count = 0;
compare_count = 0;
free(arrayIn);
}
}
}
return 0;
}
void fill_array(int *arr, int n) {
int i;
for (i = 0; i < n; i++) {
// arr[i] = (RAND_MAX + 1)*rand() + rand(); // causes integer overflow
arr[i] = rand();
}
}
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count) {
int i, j, t;
for (j = 0; j < n; j++) {
(*compare_count)++;
t = arr[j];
i = j - 1;
*swap_count = *swap_count + 2;
while (i >= 0 && arr[i]>t) { //tady chybí compare_count inkrementace
*compare_count = *compare_count + 2;
arr[i + 1] = arr[i];
(*swap_count)++;
i--;
(*swap_count)++;
}
arr[i + 1] = t;
(*swap_count)++;
}
}
void print_array(int *a, int n, int* sw, int *cc) {
int ii;
for(ii = 0; ii < n; ii++) {
if(ii%20 == 0) printf("\n");
printf("%d ", a[ii]);
}
printf("\n\nThis took %d swaps and %d comparisons\n\n", *sw, *cc);
}
You are assigning the literal value 0 to some pointers. You are also mixing "pointers" with "address-of-pointers"; &swap_count gives the address of the pointer, not the address of its value.
First off, no need to malloc here:
int *swap_count = (int*)malloc(sizeof(int)) ..
Just make an integer:
int swap_coint;
Then you don't need to do
swap_coint = 0;
to this pointer (which causes your errors). Doing so on a regular int variable is, of course, just fine.
(With the above fixed, &swap_count ought to work, so don't change that as well.)
As I told in the comments, you are passing the addresses of pointers, which point to an actual value.
With the ampersand prefix (&) you are passing the address of something.
You only use this when you pass a primitive type.
E.g. filling the array by passing an int. But you are passing pointers, so no need to use ampersand.
What's actually happening is that you are looking in the address space of the pointer, not the actual value the pointer points to in the end. This causes various memory conflicts.
Remove all & where you are inputting pointers these lines:
fill_array(&arrayIn, n);
InsertionSort(&arrayIn, n, &swap_count, &compare_count);
print_array(&arrayIn, n, &swap_count, &compare_count);
So it becomes:
fill_array(arrayIn, n);
InsertionSort(arrayIn, n, swap_count, compare_count);
print_array(arrayIn, n, swap_count, compare_count);
I also note that you alloc memory for primitive types, which could be done way simpler:
int compare_count = 0;
int swap_count = 0;
But if you choose to use the last block of code, DO use &swap_count and &compare_count since you are passing primitive types, not pointers!

K&R valid input for arrays & pointers in the swap function

I'm having trouble with the things I am and am not allowed to do with arrays and pointers in the following code:
#include <stdio.h>
#define MAX 1000
void swap (char *v[], int i, int j);
main() {
int i = 1, j = 2;
int count;
char *a = "Bill ", *b = "went ", *c = "to the ", *d = "grocery store.";
char *v[MAX];
v[0] = a;
v[1] = b;
v[2] = c;
v[3] = d;
printf("String before swapping elements at index %d and %d: \n",i,j);
for(count = 0; count < 4; ++count)
printf("%s",v[count]);
printf("\n");
swap(v,i,j);
printf("String after swapping elements at index %d and %d: \n",i,j);
for(count = 0; count < 4; ++count)
printf("%s",v[count]);
printf("\n");
system("Pause");
return 0;
}
void swap (char *v[], int i, int j)
{
char *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
Two things come to mind:
Why can't I write v[] = {a,b,c,d} after declaring *v[MAX]? In fact, I did a quick test and even this isn't allowed:
char v[MAX];
v[] = {'w','o','r','d','s'};
whereas char v[] = {'w','o','r','d','s'}; is accepted. Why is that?
Second thing, how can I re-write the for loop without having to use a magic number (in this case 4)? I tried using strlen in various ways but I got an error each time. The best I could come up with is a somewhat clumsy solution of declaring char *k; and changing the loop condition to
for(count = 0, k = v; *(k-1); ++count, ++k)
printf("%s",v[count]);
Surely there must be a more elegant way to loop through the v array?
how can I re-write the for loop without having to use a magic number
(in this case 4)?
One way of doing this, is to add a special terminator value ( usually NULL) in the array that you are iterating, e.g.
char *v[] = { a, b, c, d, NULL };
for(count = 0; v[count] != NULL; ++count)
printf("%s",v[count]);
char *v[] = { a, b, c, d};
int size = sizeof(v)/sizeof(*v);//4

Why this C programming can not run crrectly?

It's just a sample test that I want to unite the list Lb and La without repeat element. It didn't work, and returned -1073741510, I think maybe the array overflow, but I can't find where the problem is
This is my code:
#include <stdio.h>
void Union(char *La, char *Lb);
int ListLength(char *L);
void GetElem(char *L, int i, char *e);
int LocateElem(char *L, char *e, int (*comp)(char a, char b));
int compare(char a, char b);
void ListInsert(char *, int, char *);
int main(){
char *La;
char *Lb;
int i;
for(i = 0; i <= 10; ++i){
La[i] = i;
Lb[i] = i + 5;
}
La[i] = '\0';
Lb[i] = '\0';
Union(La, Lb);
for(i = 0; La[i] != '\0'; ++i){
printf("%c\n", La[i]);
}
return 0;
}
//unite La and Lb without repeat elements
void Union(char *La, char *Lb){
int La_length = ListLength(La);
int Lb_length = ListLength(Lb);
int i = 0;
char *e;
for(i; i<= Lb_length; ++i){
GetElem(Lb, i, e);
if(!LocateElem(La, e, compare))
ListInsert(La, ++La_length, e);
}
}
//caculate the length of L
int ListLength(char *L){
int i;
for(i = 0; *(L + i) != '\0'; ++i);
return i;
}
void GetElem(char *L, int i, char *e){
*e = *(L + i);
}
//search the element e in L, if exist return the location, else return 0
int LocateElem(char *L, char *e, int (*comp)(char a, char b)){
int i;
for(i = 0; *(L + i) != '\0'; ++i){
if(comp(*(L + i), *e)) return i + 1;
}
return 0;
}
//compare the element a and b
int compare(char a, char b){
if(a == b) return 1;
return 0;
}
//if e doesn't exit in L, insert the e in L
void ListInsert(char *L, int i, char *e){
int j;
for(j = ListLength(L) - 1; j >= i; --j){
*(L + j + 1) = *(L + j);
}
L[ListLength(L)] = '\0';
*(L + i - 2) = *e;
}
First, this is wrong:
char *La;
char *Lb;
int i;
for(i = 0; i <= 10; ++i){
La[i] = i;
Lb[i] = i + 5;
}
You need to reserve memory for La and Lb, for instance, by declaring them as:
char La[12];
char Lb[12];
An then this:
char *e;
for(i; i<= Lb_length; ++i){
GetElem(Lb, i, e);
should read:
char e;
for(; i<= Lb_length; ++i){
GetElem(Lb, i, &e); /* better yet: e=Lb[i] */
Finally, you're most likely looping one time too many by using <= instead of < as the for exit condition.
You have several issues. I think you need to read more about what are raw pointers, fixed length arrays, variable length arras and dynamic arrays. If you need your array to grow you can make it dynamic with malloc and realloc. Alternatively you can use a "big" array you know never will overflow.
int La[12]; // 0 to 10, plus '\0'
But this is fixed and cannt grow. You could use
int La[1000]; // if it solve yours problems
But in general you will need dynamic arrays.
Also, you need to deside if your array can hold 0 or it is used as terminator. '\0' and 0, in the form you use it are equal. Many of your for cycle dont run because the first elemnt is 0.

Resources