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';
Related
I have just coded splitting string into words.
if char *cmd = "Hello world baby", then argv[0] = "Hello", argv[1] = "world", argv[2] = "baby".
strdup function cannot be used, and I want to implement this using malloc and strcpy.
my code is below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define buf_size 128
int main() {
char *argv[16];
memset(argv, 0, sizeof(argv));
int words = 0;
char *cmd = "Hello world baby";
unsigned int len = strlen(cmd);
int start = 0;
for(unsigned int i = 0; i <= len; i++){
if(cmd[i] == ' ' | cmd[i] == '\0'){
++words;
char *w = (char *)malloc(sizeof(char)*(i-start) + 1);
strcpy(w, cmd + start);
w[i-start] = '\0';
argv[i] = w;
start = i + 1;
}
}
for(int i = 0; i < words; i++){
printf("%s\n", argv[i]);
free(argv[i]);
}
return 0;
}
I hoped that the printf function produces:
Hello
world
baby
However, when the printf() function is reached, the program triggers a segmentation fault.
Your primary problem, despite the banter in the comments about how to write your own version of strdup(), is that you really need strndup(). Eh?
You have the line:
strcpy(w, cmd + start);
Unfortunately, this copies the whole string from cmd + start into the allocated space, but you only wanted to copy (i - start) + 1 bytes including the null byte, because that's all the space you allocated. So, you have a buffer overflow (but not a stack overflow).
POSIX provides the function strndup()
with the signature:
extern char *strndup(const char *s, size_t size);
This allocates at most size + 1 bytes and copies at most size bytes from s and a null byte into the allocated space. You'd use:
argv[i] = strndup(cmd + start, i - start);
to get the required result. If you don't have (or can't use) strndup(), you can write your own. That's easiest if you have strnlen(), but you can write your own version of that if necessary (you don't have it or can't use it):
char *my_strndup(const char *s, size_t len)
{
size_t nbytes = strnlen(s, len);
char *result = malloc(nbytes + 1);
if (result != NULL)
{
memmove(result, s, nbytes);
result[nbytes] = '\0';
}
return result;
}
This deals with the situation where the actual string is shorter than the maximum length it can be by using the size from strnlen(). It's not clear that you are guaranteed to be able to access the memory at s + nbytes - 1, so simply allocating for the maximum size is not appropriate.
Implementing strnlen():
size_t my_strnlen(const char *s, size_t size)
{
size_t count = 0;
while (count < size && *s++ != '\0')
count++;
return count;
}
"Official" versions of this are probably implemented in assembler and are more efficient, but I think that's a valid implementation in pure C.
Another alternative in your code is to use the knowledge of the length:
char *w = (char *)malloc(sizeof(char)*(i - start + 1));
memmove(w, cmd + start, i - start);
w[i-start] = '\0';
argv[i] = w;
start = i + 1;
I note in passing that multiplying by sizeof(char) is a no-op since sizeof(char) == 1 by definition. You should include the + 1 in the multiplication in general (as I've reparenthesized the expression). If you were dealing with some structure and wanted N + 1 structures, you need to use (N + 1) * sizeof(struct WhatNot) and not N * sizeof(struct WhatNot) + 1. It's a good idea to head off bugs caused by sloppy coding practices while you're learning, even though there's no difference in the result here.
There are those who excoriate the cast on the result of malloc(). I'm not one of them: I learned to program on a pre-standard C system where the cast was crucial because the char * address of an object was different from the address of the same memory location when referenced via a pointer to a type bigger than a char. That is, the short * address and char * address for the same memory location had different bit patterns. Not casting the result of malloc() led to crashes. (I observe that the primary excuse given for rejecting the cast is "it may hide errors if malloc() is not declared". That excuse went by the wayside when C99 mandated that functions must be declared before being used.)
Warning: no compiler was consulted about the validity of any of the code shown in this answer. Nor was the sanity of the overall algorithm tested.
You have:
if(cmd[i] == ' ' | cmd[i] == '\0'){
That | should be ||.
In the main function, I use malloc() to create an unsigned char array:
int main()
{
int length = 64;
unsigned char *array = (unsigned char *)malloc(length * sizeof(unsigned char));
...
change_size(array, length);
}
change_size() defined in .h:
void change_size(unsigned char* arr, int len);
In the change_size function, I will use realloc() to increase the array size:
void change size(unsigned char* arr, int len)
{
printf("%d\n", len);
len = len + 16;
printf("%d\n", len);
arr = (unsigned char *)realloc(arr, len * sizeof(unsigned char));
int new_len = sizeof(arr)/sizeof(arr[0]);
printf("%d\n", new_len);
}
The printf() show me:
64
80
8
The array size in the main() also needs to be updated.
Then how to change this array size correctly?
You need to pass your parameters as pointers if you want to change their value back in the caller. That also means you pass your array pointer as a pointer, because realloc might change it:
int change_size(unsigned char **arr, int *len)
{
int new_len = *len + 16;
unsigned char *new_arr = realloc(*arr, new_len);
if (new_arr) {
*len = new_len;
*arr = new_arr;
}
return new_arr != NULL;
}
Here I've modified change_size to suit, and also added a return value to indicate success, since realloc can fail to resize the memory. For clarity, I removed the printf calls. Oh, and I also removed the cast, since that is not valid in C.
Example usage:
if (!change_size(&array, &len))
{
perror("change_size failed");
}
One final note is that you can use your change_size function for the first allocation too, rather than calling malloc. If the first argument to realloc is NULL, it does the same thing as malloc.
First C is not babysitter language,
You only need basic things then you can do everything,
Just try hard to totally understand basic.
#include <stdio.h>
#include <stdlib.h>
int main(){
int G1_Len=20;
int G2_Len=40;
char* G1=(char*)malloc(sizeof(char)*G1_Len);
char* G2=(char*)malloc(sizeof(char)*G2_Len);
printf("This is G1's Size:%d,Becuz G1 is Pointer\n",sizeof(G1));
printf("%d\n",sizeof(G2));
printf("This is what you need just add a variable remainber your size\n%d\n",G1_Len);
printf("%d\n",G2_Len);
/*alloc and free is a pair of memory control you need,remember least function thinking more is tip of C*/
/*if you need alot of function but you cant control all try c++*/
/*and if in c++ using new and delete dont use malloc free*/
free(G1);
free(G2);
G1=NULL;
G2=NULL;
G1_Len=22;
G1=(char*)malloc(sizeof(char)*G1_Len);
//Now you have 22 bytes of char array
free(G1);
return 0;
}
Okay I answer it. #Chipster
#include <stdio.h>
#include <stdlib.h>
int change_size(char** arr, int len)
{
char* nar=(char*)malloc(sizeof(char)*(len+16));
if(nar){
free(* arr);
*arr=nar;
nar[10]='K';//this will let you know its right
return len+16;
}
return len;
}
int main(){
int G1_Len=20;
int G2_Len=40;
char* G1=(char*)malloc(sizeof(char)*G1_Len);
char* G2=(char*)malloc(sizeof(char)*G2_Len);
printf("This is G1's Size:%d,Becuz G1 is Pointer\n",sizeof(G1));
printf("%d\n",sizeof(G2));
printf("This is what you need just add a variable remainber your size\n%d\n",G1_Len);
printf("%d\n",G2_Len);
/*alloc and free is a pair of memory control you need,remember least function thinking more is tip of C*/
/*if you need alot of function but you cant control all try c++*/
/*and if in c++ using new and delete dont use malloc free*/
free(G1);
free(G2);
G1=NULL;
G2=NULL;
G1_Len=22;
G1=(char*)malloc(sizeof(char)*G1_Len);
//Now you have 22 bytes of char array
printf("%d\n",G1);
G1_Len=change_size(&G1,G1_Len);
printf("%c\n",G1[10]);
printf("%d\n",G1);
printf("%d\n",G1_Len);
free(G1);
return 0;
}
I am playing around a bit in C and trying to write a test program for kind of oop in c programming. I get the Error of the headline in Visual Studio 2010. In using gcc i don't get this error.
Can anyone point me to what i am doing wrong, besides using the wrong language for oop, and other off topic suggestions.
It seems like the error occurs when i free the top object in string_dispose, but i am not shure if that really says a lot about the location of the error.
Also any suggestions regarding code improvements are welcome. Using array syntax is not an option, because i want to try out pointer arithmetic.
The header file "strings.h":
#ifndef STRINGS_H
#define STRINGS_H
struct strings
{
char* s;
int len;
};
typedef struct strings string;
void string_init(string* s, char* chars, int len);
string* string_new(char* chars, int len);
void string_dispose(string* s);
#endif
The source file "strings.c":
#include "strings.h"
#include <stdlib.h>
void string_init(string* self, char* chars, int len)
{
int i;
self->s = (char*)malloc((len + 1) * sizeof(char*));
for (i = 0; i < len; i++)
{
*(self->s + i) = *(chars + i);
}
*(self->s + len) = '\0';
self->len = len;
}
string* string_new(char* chars, int len)
{
string* self;
self = (string*)malloc(sizeof(string*));
string_init(self, chars, len);
return self;
}
void string_dispose(string* self)
{
free(self->s);
free(self);
}
The main file:
#include <stdlib.h>
#include <stdio.h>
#include "strings.h"
int main(int argc, char* argv)
{
string* s;
int n = 5;
char* x = (char*)malloc((n + 1) * sizeof(char*));
x[0] = 'f';
x[1] = 'u';
x[2] = 'b';
x[3] = 'a';
x[4] = 'r';
x[5] = '\0';
s = string_new(x, n);
printf("the string: %s\n", s->s);
printf("the length: %d\n", s->len);
string_dispose(s);
printf("This is way more important");
return 0;
}
When you try to allocate memory for string, you only allocate enough memory for a pointer (string*):
self = (string*)malloc(sizeof(string*));
You should allocate sizeof(string) instead, since you want enough space to store the whole struct, not just a pointer to one. Since sizeof(string*) is smaller than sizeof(string), the other code writes outside of the allocated area, causing heap corruption.
Similarly, when mallocing memory for the characters, the size should be (len + 1) * sizeof(char).
There's a function. It is add_lexem and adds an element (char *) in the end of specified array and. If no memory left, it allocates some extra memory (100 * sizeof(char *)). That function causes segfault, which is the problem.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void add_lexem(char **lexems, int *lexemsc, int *lexem_n, const char *lexem)
{
if (*lexem_n >= *lexemsc) {
lexems = realloc(lexems, sizeof(char *) * (*lexemsc + 100));
*lexemsc += 100;
}
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
lexems[*lexem_n] = for_adding;
(*lexem_n)++;
}
int main(void)
{
char **D = malloc(sizeof(char *) * 2);
int lexemsc = 2;
int lexem_n = 0;
add_lexem(D, &lexemsc, &lexem_n, "MEOW");
printf("%s\n", D[0]);
add_lexem(D, &lexemsc, &lexem_n, "BARK");
printf("%s\n", D[1]);
// in this place lexem_n becomes equal lexemsc
add_lexem(D, &lexemsc, &lexem_n, "KWARK");
printf("%s\n", D[2]);
return 0;
}
The output must be
MEOW
BARK
KWARK
but it is
MEOW
BARK
Segmentation fault (core dumped)
You're passing your lexeme parameter by value, when it should be by address:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
// removed unused void ccat(char *str, char c)
void add_lexem(char ***lexems, int *lexemsc, int *lexem_n, const char *lexem)
{
if (*lexem_n >= *lexemsc) {
*lexems = realloc(*lexems, sizeof(char *) * (*lexemsc + 100));
*lexemsc += 100;
}
char *for_adding = malloc(sizeof(char) * strlen(lexem)+1);
strcpy(for_adding, lexem);
(*lexems)[*lexem_n] = for_adding;
(*lexem_n)++;
}
int main(void)
{
char **D = malloc(sizeof(char *) * 2);
int lexemsc = 2;
int lexem_n = 0;
add_lexem(&D, &lexemsc, &lexem_n, "MEOW");
printf("%s\n", D[0]);
add_lexem(&D, &lexemsc, &lexem_n, "BARK");
printf("%s\n", D[1]);
// in this place lexem_n becomes equal lexemsc
add_lexem(&D, &lexemsc, &lexem_n, "KWARK");
printf("%s\n", D[2]);
return 0;
}
Output
MEOW
BARK
KWARK
Note: Triple indirection (i.e. a 3-start-programming) is not something to enter into lightly, though it actually fits what you appear to be trying to do here. Read the above code carefully and make sure you understand how it works.
Edit: added terminator space for added string. (don't know why I missed it, since it was what everyone else seemed to be catching on first-review, duh).
Note: See #wildplasser's answer to this question. Honestly it is the best way to do this, as it tightens the relationship between the string pointer array and the magnitude of said-same. If it is possible to retool your code to use that model, you should do so, and in-so-doing select that answer as the the "correct" solution.
Alternative to avoid the three-star-programming: put everything you need inside a struct:
struct wordbag {
size_t size;
size_t used;
char **bag;
};
void add_lexem(struct wordbag *wb, const char *lexem)
{
if (wb->used >= wb->size) {
wb->bag = realloc(wb->bag, (wb->size+100) * sizeof *wb->bag );
wb->size += 100;
}
wb->bag[wb->used++] = strdup(lexem);
}
The main problem is that you are passing D to the function by value: the assignment
lexems = realloc(...);
has no effect on D. In cases when realloc performs reallocation, D becomes a dangling pointer, so dereferencing it becomes undefined behavior.
You need to pass D by pointer in the same way that you pass lexemsc and &lexem_n, so that the realloc's effect would be visible inside the main function as well.
In addition, your add_lexem does not allocate enough memory for the string being copied: strlen does not count the null terminator, so these two lines
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
write '\0' one byte past the allocated space.
The problem may come from :
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
try char *for_adding = malloc(sizeof(char) * (strlen(lexem)+1)); to leave some space for the '\0 character.
Edit : and #WhozCraig seems to be right !
Bye,
I'm relatively a beginner in programming in C and am getting super confused with arrays and pointers.
Basically what I'm trying to do is extend a string that contains binary to the designated length len; (i.e. len=8 for num[]=101 would produce "00000101").
Can someone help me understand what's wrong with this?
const char * extendBinary(char num[], int len) {
char *number = #
int length = len;
int difference;
if(strlen(*num)<len) {
difference = len-strlen(num);
while(difference>0)
{
&number = strcat("0", &number);
difference--;
}
}
return number;
}
Your problems start with your specification. If I understand you correctly, you want to have a function where you pass an array of characters and a length. The size of your array of input characters will be between 1 and len? However, your function has no way of knowing what the size of your array num is. If you wanted this to work, you would need to define your function as
const char * extendBinary(char *num, size_t num_len, int len);
so that your function doesn't overrun your buffer pointed to by num. Note that I replaced char num[] with char *num as this is the common mechanism for passing a pointer. You cant pass pointers to arrays and then dereference that pointer and get back the original type (that includes its size) -- that's just one thing that C doesn't let you do, so just use a normal pointer and a separate size variable.
Finally, you'll have to deal with memory allocation unless you want a memory leak. Thus, you could simply say that whom ever calls extendBinary should free it's return value when done with it.
const char * extendBinary(char *num, size_t num_len, int len) {
char *ret = malloc(len + 1);
int i;
memset(ret, '0', len);
ret[len] = 0;
strncpy(&ret[len - num_len], num, num_len);
return ret;
}
int main(void) {
char arr[] = {'1', '0', '1'};
const char *formatted = extendBinary(arr, sizeof(arr), 8);
printf("%s\n", formatted);
free(formatted);
return 0;
}
this is wrong.
strcat("0", &number);
A weird way to fix you code would be this:
char temp[32] = {};
...
...
while(difference>0)
{
strncat(temp, "0", 31 - strlen(temp));
difference--;
}
strncat(temp, num, 31 - strlen(temp));
strncpy(num, temp, len);
Note, I am writing this code just to help you understand how strcat() works, there is much better ways to do what you are trying to do.
You cannot concatenate something to a const string, you must have entire control of what is happening into you code, and where your code is writing. Do you know where is the pointer to "0" in your source?
How do you set up num? If it's really an array of characters rather than a string, there's no requirement that it be null terminated, unless it's a global/static. If you set it up like so in a function:
char str[10];
str[0] = '1';
str[1] = '0';
str[2] = '1';
than your strlen will get whatever, depending upon whatever junk happens to be in num.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//case 1: for num[9]="101";
char *extendBinary1(char num[], int len) {
int num_len = strlen(num);
memmove(num + (len - num_len), num, num_len);
memset(num, '0', (len - num_len));
return num;
}
//case 2: for "101";//pointer to const char
char *extendBinary2(const char num[], int len) {
int num_len = strlen(num);
char *number = calloc(len + 1, sizeof(char));
memset(number, '0', (len - num_len));
return strcat(number, num);
}
int main(void){
char num[9] = "101";
char *number = extendBinary2("101", 8);//dynamic allocate
printf("%s\n", extendBinary1(num, 8));
printf("%s\n", number);//free(number);
return 0;
}