c language How I free a pointer after I move it - c

what I wanna to do is get space separated words into a 2d array.what I am thinking is replace space by a '\0',so I can copy the string to array.And then add the string pointer to the place after '\0'.keeping do it till the last.But when I done it ,I consider how can I free the pointer.I consider maybe I can save it first so I use char *t = s.But when I free the t I get a segment error.so how should i free the s pointer after it move to another place.
beside this,I also have some questions:
1.after I malloc a sizeof(char)*15 memory ,I expect printf strlen(s) I can print 15,but I get 0,why?If I wanna know the size of s now,how should I do?
2.after strcpy str to s,the strlen s become 11.But I malloc size of 15,where will the left memory go? does that effect program?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(){
char buf[10][5];
char *str = "10 8 6 9 76";
char *s;
char *t = s;
s = (char *)malloc(sizeof(char)*15);
printf("strlen 1 s:%d\n",strlen(s));
memset(s,0x00,sizeof(char)*15);
printf("strlen 2 s:%d\n",strlen(s));
strcpy(s,str);
int n = strlen(s);
int i = 0;
int j = 0;
int k = 0;
for( i = 0; i < n; i++ ){
if( s[i] == ' '){
s[i] = '\0';
strcpy( buf[k], s);
s += (i+1);
k++;
n = n - i - 1;
i = 0;
}
}
printf("s:%s\n",s);
strcpy( buf[k], s );
for( j = 0; j<= k; j++ ){
printf("buf[%d]:[%s]\n",j,buf[j]);
}
printf("j:%d\n",j);
free(t);
return 0;
}

The main problem is that you are assigning s to t before allocating memory for s:
char *t = s;
and then you try to free t which point to an un-initialised memory.
If you compile your code with -Wall you will get a warning.
You should set t = s after the memory allocation of s.
Also, always check the return value of malloc (there is no need to cast it):
s = malloc(sizeof(char)*15);
if (s == NULL) {
// Error!
return 1
}

Related

How to add string elements successively in C?

I want to add string elements successively, for example st[]="morty", and I want to repeat its elements for example seven times. It should be st[]="mortymo". I wrote a function which is at below. (The length function is strlen).
void repeat(char* st,int n){
int i,k=0,l=length(st);
char* ptr;
ptr=(char*)malloc((n+1)*sizeof(char));
for (i=0;i<n;i++){
*(ptr+i)=*(st+k);
k++;
if(k==l)k=0;
}
}
The program below repeats characters from the original string.
Comments in the code:
#include<stdio.h>
#include<stdlib.h>
char* repeat(const char* st, size_t n){
// use `const` to note that pointer `st` will not be modified
// for purity you may want to use type `size_t` since returning type of strlen is `size_t`
size_t i, k=0;
size_t l = strlen(st);
// do not use (char *) cast
char* ptr = malloc((n+1)*sizeof(char)); // allocate enough room for characters + NULL
for (i=0; i< n; i++)
{
ptr[i] = st[k]; // use index for readability
k++;
if (k == l)
k=0;
}
ptr[i] = 0; // terminate the string
return ptr;
}
int main( )
{
char *str = "12345";
str = repeat(str, 15);
printf("%s\n",str);
free (str); // free the allocated memory inside the repeat function
return 0;
}
OUTPUT:
123451234512345
In your repeat function, you allocated ptr to hold the repeated string, but you didn't return or assign it to st. You can modify your repeat function as follows:
char* repeat(char* st,int n){
int i,k=0,l=strlen(st);
char* ptr;
ptr=(char*)malloc((n+1)*sizeof(char));
for (i=0;i<n;i++){
*(ptr+i)=*(st+k);
k++;
if(k==l)k=0;
}
*(ptr+n) = '\0';
return ptr;
}
/* some code*/
char *st = "morty";
st = repeat(st, 7);
Such that you are storing the result of the repeated string in st after.
If I have understood the assignment correctly then you need a function like that one shown in the demonstrative program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * repeat( const char *s, size_t n )
{
char *p = NULL;
size_t len = strlen( s );
if ( len == 0 ) n = 0;
p = ( char * )malloc( n + 1 );
if ( p )
{
size_t i = 0;
for ( size_t j = 0; i < n; i++ )
{
p[i] = s[j];
if ( ++j == len ) j = 0;
}
p[i] = '\0';
}
return p;
}
int main(void)
{
char *s = "Hi, Zusaetlich.";
char *p = repeat( s, 2 * strlen( s ) );
puts( p );
free( p );
return 0;
}
The program output is
Hi, Zusaetlich.Hi, Zusaetlich.
Pay attention to that the function is designed such a way that if the original string is empty then the resulted string is also empty because there is nothing to repeat.
As for your function then it has at least a memory leak because the memory allocated in the function is not freed.
Also as the original string is not changed then the corresponding parameter should be qualified with the const specifier. And the second parameter should have type size_t because at least the function strlen has the return type size_t.
So the function should be declared as it is shown in the demonstrative program.
Since you don't intend to modify the contents of st, go ahead and declare it as const. Since you intend to allocate a new string in your function, you should return it to the caller.
char *repeat(const char* st,int n){
k is unnecessary for your problem. Call the standard functions.
int i,l=strlen(st);
char* ptr;
Don't cast the result of malloc, as this can mask a fatal error in C. sizeof(char) is always 1. Check the result of the malloc call for success.
ptr=malloc(n+1);
if (ptr == NULL) return NULL;
for (i=0;i<n;i++){
Access arrays idiomatically with []. Note that k increments whenever i does, but you are applying a modulo operation of k. However, C has a modulo operator, which you can use directly on i.
ptr[i]=st[i%l];
}
Make sure the new string is NUL terminated. Your function is declared to return a result, but your implementation fails to do so.
ptr[n] = '\0';
return ptr;
}
C has many functions you can call to do the copying for you rather than the byte by byte loop you have written. There is simplicity in your implementation, but below is an alternative, that also includes additional error checking that is lacking in your solution.
(Some may balk at the use of sprintf, but it is being used correctly.)
char *
repeat (const char *st, int n) {
int l = st ? strlen(st) : 0;
char *ret = (st && n > 0 ? malloc(n+1) : 0), *p = ret;
while (ret && n > 0) {
p += sprintf(p, "%.*s", (l < n ? l : n), st);
n -= l;
}
return ret ? ret : "(nil)";
}
Try it online!

Copying argv and checking it for a palindrome

I'm writing a program to check for palindromes. I recently picked up C and was wondering is there a reason why my take on it won't work? Does it have something to do with my use of directly copying argv into a char array
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc,char *argv[]){
int i;
int a;
int size;
for(a = 1; a < argc; a++){
char *reverseThis = argv[a];
char *normal = argv[a];
size = strlen(reverseThis);
for(i = 0; i < size; i++){
reverseThis[i] = normal[size - i - 1];
}
for(i = 0; i < size; i++){
reverseThis[i] = tolower(reverseThis[i]);
normal[i] = tolower(normal[i]);
}
if(strcmp(reverseThis,normal)==0){
printf("\"%s\": on palindromi\n",argv[i]);
}
else
printf("\"%s\": ei ole palindromi\n",argv[i]);
}
return 0;
}
In your code you are not copying the strings, you assigned both normal and reverseThis to same string argv[a].In reverseThis you need to copy argv[a] after allocating memory.
Just modify your code in forloop:
for(a = 1; a < argc; a++){
char *normal = argv[a];
size = strlen(normal);
char *reverseThis = (char*)malloc((size+1)*sizeof(char));
int j=0;
for(i = size-1; i >= 0; i++){
reverseThis[j++] = normal[i];
}
reverseThis[j]='\0';
.
.
You are using an incorrect approach.
For starters this loop
for(i = 0; i < size; i++){
reverseThis[i] = normal[size - i - 1];
}
copies the right half of the string in reverse order in the left half of the string totally overwriting its left part.
For example if you have a string like this "123456" then after the loop it will look like "654456"
This comparison also does not make sense
if(strcmp(reverseThis,normal)==0){
because the both pointers point to the same string. So the condition always yields true.
Take into account that these declarations
char *reverseThis = argv[a];
char *normal = argv[a];
do not copy the original string pointed to by argv[a]. The declared pointers just point to the first character of the same string.
And here is a typo
printf("\"%s\": on palindromi\n",argv[i]);
^^^
The task can be done simpler without changing the strings.
For example
size_t n = strlen( argv[a] );
size_t i = 0;
while ( i < n / 2 && tolower( ( unsigned char )argv[i] ) == tolower( ( unsigned char )argv[n -i - 1] ) ) ++i;
if ( i == n / 2 )
{
printf("\"%s\": on palindromi\n", argv[a]);
}
else
{
printf("\"%s\": ei ole palindromi\n",argv[a]);
}
If you indeed need to copy the strings then either declare variable length arrays (if the compiler supports them) or allocate arrays dynamically. For example (declaring variable length arrays):
size = strlen( argv[a] );
char reverseThis[size + 1];
char normal[size + 1];
strcpy( reverseThis, argv[a] );
strcpy( normal, argv[a] );
You don't need to reverse the string and compare to find out whether the input string is palindrome or not.
You can simply compare the characters of the string starting from both ends of the string and move one character forward from the start of the string and one character backward from the end of the string. If all character matches till you reach to mid of string then the string is palindrome otherwise not a palindrome.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc,char *argv[]){
int i, a, size;
for(a = 1; a < argc; a++){
char *ptr= argv[a];
int notpalindrom = 0;
size = strlen(ptr) - 1;
for(i = 0; i < size; ){
if (tolower(ptr[i++]) != tolower(ptr[size--])){
notpalindrom = 1;
break;
}
}
if (notpalindrom)
printf ("%s is not palindrom\n", ptr);
else
printf ("%s is palindrom\n", ptr);
}
return 0;
}
The first "if" take from argv in index "i", i == to the last change that has changed in the last "for", in your case i == 4, and the program crashed cause their isn't string in that member, to fix that you should change the "i" to 0 before the "if".

Why my program skips a for cicle? C

im trying to code a function that splits a string onto multiple ones, i know I have alot of allocated space not freed, I'm just testing this bit but valgrind displays me
Conditional jump or move depends on uninitialised value(s)
==25613== at 0x4C2DB3C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25613== by 0x40090C: split (strutil.c:32)
==25613== by 0x400A00: main (strutil.c:45)
==25613== Uninitialised value was created by a stack allocation
==25613== at 0x400720: split (strutil.c:9)
a few similar errors and then sigsem and closes. my concern is that when i run it with gdb in that for circle thats supposed to count the ',' it circles as expected until it reaches the value ',' then skips entire cicle but the i++ and keeps going. Why does it do that? I watched over gdb and all the parameters (str[i] , sep) have the correct values inside at the moment before the conditional.
#include "strutil.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char** split(const char* str, char sep){
size_t cant = 2;
size_t i;
for(i = 0; i < strlen(str); i++){//this is line 9
if(str[i] == sep)
cant ++;
i++;
}
size_t corte[cant];
i = 0;
corte[0] = 0;
size_t j = 1;
size_t cant_corte[cant];
for(i = 0; i < strlen(str); i++){
if(str[i] == sep){
corte[j] = i + 1;
cant_corte[j - 1] = corte[j] - corte[j - 1];
//printf("pasa\n");
j++;
}
printf("pasa\n");
i++;
}
char** strv = malloc(sizeof(char*) * cant);
if (strv == NULL)return NULL;
for(i=0; i < cant; i++){
strv[i] = malloc(sizeof(char) * cant_corte[i]);
if (strv[i] == NULL)return NULL;
strncpy(strv[i], str + corte[i], cant_corte[i-1]);
strcat(strv[i], "\0");
}
strv[cant + 2] = NULL;
return strv;
}
int main(){
char* eje = "abc,defg";
printf("%s\n", eje);
char r = ',';
char** prueba = split(eje, r);
printf("%s\n", prueba[0]);
getchar();
return 0;
}
If you do not want your i variable to continue to increment, then make sure in your for loop you do not increment i, and instead depend on the for loop to do its' job. ( increment i every time the condition is true ).

Difficulties with creating the Cartesian product of a pointer to char pointer

As input I have a pointer to char pointer containing:
{"ab", "cd"}
As output I need to create the following Cartesian product:
{"abab", "abcd", "cdab", "cdcd"}
I created a function that receives "ab, cd" and a pointer to char pointer that is meant to hold the resulting set. Although everything seems to be working fine inside the function, once it gets exited, my output remains empty. I suppose I'm doing something wrong during the concatenation but I'm not sure what.
This is how my code looks like:
#include <stdio.h>
void Permute(char**, int, char**);
main() {
// my input
int words = 2;
char **input;
input = malloc(sizeof(char*) * words);
input[0] = "ab";
input[1] = "cd";
// compute how much memory we need
char **output;
output = malloc(sizeof(char*) * (words * 2));
// start permutation
Permute(input, words, output);
// show output
int i = 0;
for(i = 0; i < (words * 2); ++i) {
// should print: {abcd, abab, cdab, cdcd}
// but nothing gets printed
printf("%s\n", output[i]);
}
free(input);
free(output);
}
void Permute(char **input, int words, char **output){
int i = 0, j = 0, k = 0;
char str[5];
for(i = 0; i < words; ++i) {
for(j = 0; j < words; ++j) {
strcpy (str, input[i]);
strcat (str, input[j]);
output[k] = str;
// at this point concatenation is printed correctly
printf("%s\n", output[k]); correctly
++k;
}
}
}
Edit
Thanks to Goz's comment I updated my function. Now, a pointer to char gets allocated, is pointed to the concatenation and is then stored inside output[k]. This way no data is lost when exciting the funcion:
void Permute(char **input, int words, char **output){
int i = 0, j = 0, k = 0;
char *p;
for(i = 0; i < words; ++i) {
for(j = 0; j < words; ++j) {
p = malloc(sizeof(char*) * 5);
strcpy(p, input[i]);
strcat (p, input[j]);
output[k] = p;
printf("%d %s \n", k, output[k]);
++k;
}
}
}
Edit
The buffer holding the result gets allocated before passing it over to the Permute function:
// compute how much memory we need
// allocate space for 4 pointers to char
char **output = malloc(sizeof(char*) * 4);
int i = 0;
// pre-allocate space for every pointer
for(i = 0; i < 4; i++)
output[i] = malloc( sizeof( char ) * 5 );
Edit
Free all memory pointed to by char pointer before cleaning up the pointer to char pointer:
// free memory
for(i = 0; i < 4; i++ )
free( output[i] );
free(output);
for(i = 0; i < 2; i++ )
free(input[i]);
free(input);
There are a couple of issues. Firstly you allocate a char*. You then assign it to a char** and expect it to have 2 dimensionality. It doesn't. You'd need to malloc a set of char* pointers (4 * whatever your pointer size is ... ie sizeof( char* )) then malloc 5 bytes for each of those pointers.
Furthermore in Permute you overwrite the pointer value with the pointer to str (which doesn't exist outside the function). You ought to be strcpy'ing the contents of str to output[k].
In answer to the comment: Yes that will work but it would be advisable to allocate the buffer before you go into the loop.
ie
char** ptr = malloc( sizeof( char* ) * 4 );
for( int i = 0; i++; i < 4 )
{
ptr[i] = malloc( sizeof( char ) * 4 ); // sizeof( char ) == 1 but its a good habit to get into.
}
Then as said before strcpy the temporary array into the relevant char* array.
Furthermore remember that when you free the memory you need to do the opposite of the loop above. ie dealloc the 4 individual arrays and then dealloc the array of pointers. ie:
for( int i = 0; i++; i < 4 )
{
free( ptr[i] );
}
free( ptr );
ie all 5 occasions malloc is called are met with a corresponding free. If you free the array of ptr first you cannot guarantee that the memory is valid. Therefore the 4 pointers stored in that array may no longer be valid. So free them first then the array of pointers.
char str[5]; in Permute is on the stack and lost after you exit Permute. output[k] will point to an undefined place once you exit Permute.
output = malloc(sizeof(char*) * (words * 2));
Ok, you created output[0], output[1], ... but what are their values?
output[0] is a char * ... where does it point to?
And you cannot copy the address of a local variable in Permute (str) to output. That object ceases to exist once the function returns.

Help with reversing a string in C

I am trying to reverse a character string in C
Here is what I have
void reverse(char str[]) {
int i = 0;
int length;
// Get string length
for (i = 0; str[i] != '\0' ; ++i) {
length = i;
}
char reversed[1000];
int j;
j = 0;
// Reverse it
for (j = 0; j < length ; ++j) {
reversed[j] = str[length - j];
}
}
I know that reversed contains the string reversed, but I'm not sure how to modify the original str without throwing away data I need.
I also don't know how to set strto reversed without looping again.
Would it be acceptable to do another...
int m;
m = 0;
for (m = 0; m < length ; ++m) {
str[j] = reversed[j];
}
Usually I'd say this many loops smells, but I'm also still quite unfamiliar with the language so I'm not sure...
Update
Thanks for all the answers guys, and I appreciate the edits too!
I ended up going with this...
int main() {
char str[] = "Reverse me!";
int length;
for (length = 0; str[length] != '\0'; length++) {
}
printf("length => %d chars\n", length);
int j, k;
char c;
for (j = 0, k = length - 1; j < k; j++, k--) {
c = str[k];
str[k] = str[j];
str[j] = c;
}
printf("reversed => %s\n", str);
return 0;
}
Some things I now know...
There is a strlen() like in PHP. However, it has not been discussed in the book yet, plus I need to get familiar with null terminated strings.
A for loop can assign and do multiple things that are comma separated. I never knew this!
So asking was worthwhile :)
You want to do an in-place reversal. Here's a standard algorithm:
// taken from The C Programming Language
// by Brian Kernighan and Dennis Ritchie (K&R)
void reverse(char s[])
{
int c, i, j;
for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
Note that strlen pretty much replaces your original first loop. It's one of the many standard string manipulation routines available from string.h.
See also
Wikipedia/In-place algorithm
Wikipedia/string.h
Wikipedia/C Standard Library
You can use either of the two methods below, depending on whether you're comfortable with pointers or not. It will also be worthwhile looking at them side-by-side when you satrt learning about pointers so you can better understand how they map to each other.
This is a full program for testing purposes:
#include <stdio.h>
#include <string.h>
// The pointer version.
void reverse1 (char *str) {
char t; // Temporary char for swapping.
char *s = str; // First character of string.
char *e = &(s[strlen(s)-1]); // Last character of string.
// Swap first and last character the move both pointers
// towards each other. Stop when they meet or cross.
while (s < e) {
t = *s;
*s++ = *e;
*e-- = t;
}
}
// The array version.
void reverse2 (char *str) {
char t; // Temporary char for swapping.
int s = 0; // First character of string.
int e = strlen(str)-1; // Last character of string.
// Swap first and last character the move both pointers
// towards each other. Stop when they meet or cross.
while (s < e) {
t = str[s];
str[s++] = str[e];
str[e--] = t;
}
}
int main (void) {
char x[] = "This is a string for reversing.";
printf ("Original: [%s]\n", x);
reverse1 (x);
printf ("Reversed: [%s]\n", x);
reverse2 (x);
printf (" Again: [%s]\n", x);
return 0;
}
and the output is:
Original: [This is a string for reversing.]
Reversed: [.gnisrever rof gnirts a si sihT]
Again: [This is a string for reversing.]
Comments on your code:
void reverse(char str[]) {
int i = 0;
int length;
// Get string length
for (i = 0; str[i] != '\0' ; ++i) {
length = i;
}
Rather than copying the i to length every time you could just wait until the end.
size_t len = 0; // size_t is an unsigned integer that is large enough to hold the sizes
// of the biggest things you can have (32 bits on 32 bit computer,
// 64 bits on a 64 bit computer)
char * s = str;
while (*s) {
len++;
s++;
}
Though the compiler would probably be able to make this optimization for you.
You should know, though, that there is a standard string function strlen ( #include <string.h> )which will measure the length of a char string using the same general algorithm (look for the end) but is usually optimized for the target processor.
len = strlen(str);
Your code again:
char reversed[1000];
Using big arrays are good for learning and simple examples, but you can also allocate memory dynamically based on the size you now know you need. The standard function for doing this is malloc which is in stdlib.h (also in malloc.h). Memory allocated with this function should also be freed, though.
int * p = malloc( 8 * sizeof(int) ); // allocate an array of 8 ints
/* ... work on p ... */
free(p);
/* ... don't access the memory pointed to by p anymore ... */
p = 0;
There are also other functions in the malloc family. There's calloc, which allocates memory and clears sets it to 0. There is also a function called strdup (which isn't in standard C, but is very widely available in string.h) which takes a string and allocates a duplicate of it. It is really just:
char * strdup(const char * str) {
size_t len = strlen(str);
char * s = malloc(len+1);
if (!s) {
return s;
}
return strcpy(s,str); // This could have been memcpy since you know the size
// and memcpy might have been faster on many processors
}
Another useful memory allocation function is alloca (not in the C standard, but widely available and similar functionality is available with variable length arrays in C99). It is great, but works differently from malloc. It allocates memory that is only useable until the current function returns because this memory is allocated in the same way as memory for local variables (from the stack).
More of your code:
int j;
j = 0;
// Reverse it
for (j = 0; j < length ; ++j) {
reversed[j] = str[length - j];
}
The code:
void reverse_in_place(char * str, size_t len) {
size_t i, j;
for (i = 0, j = len - 1; i < j ; i++, j--) {
char a = str[i];
char z = str[j];
str[i] = z;
str[j] = a;
}
}
should swap the order of the string without making a copy of it. For strings with odd length it won't try to swap the middle char with itself.
Reversing a string in C using pointers
#include<stdio.h>
char *srcptr = "Hello!";
char *destptr;
unsigned int length = 0;
void main(void)
{
while(*(ptr++) != '\0')
{
length++;
}
//at the end of while loop, pointer points to end of string
while(length--)
{
*destptr++ = *ptr--;
}
//append null at the end
*destptr = '\0';
printf("%s",ptr);
}

Resources