#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define SUCCESS 0
#define FAILURE -1
int str_rev(char **s, char **d){
int count = 0;
if(s == NULL || d == NULL){
printf("\n Invalid address received! \n");
return FAILURE;
}
else{
while(**s != '\0'){
**s++;count++;
}
while(count > 0){
**d++ = **s--;count--;
}
**d = '\0';
return SUCCESS;
}
}
int main(){
int ret_val = SUCCESS;
char *a = "angus";
char *b;
b = malloc((strlen(a) * sizeof(*a)) + 1);
ret_val = str_rev(&a,&b);
if(ret_val == FAILURE){
printf("\n String is not reversed! going to quit! \n");
free(b);
return FAILURE;
}
printf("\n b:%s \n",b);
free(b);
return SUCCESS;
}
I am writing a simple program without the use of predefined function for string reversal. But this throws me a segmentation fault. I beleive i'm accessing the correct memory address.
EDITED:
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define SUCCESS 0
#define FAILURE -1
int str_rev(char *s, char **d){
int count = 0;
if(s == NULL || d == NULL){
printf("\n Invalid address received! \n");
return FAILURE;
}
else{
while(*s != '\0'){
s++;count++;
}
s--;
while(count > 0){
printf("\n *s:%c \n",*s); // prints the values correctly in the reverse order
*(*d)++ = *s--;count--;
printf("\n **d:%c \n",*((*d)-1)); // doesnt print the values, after the assignement
}
**d = '\0';
printf("\n s:%s *d:%s \n",s,*d); // both s and d doesnt print the values copied
return SUCCESS;
}
}
int main(){
int ret_val = SUCCESS;
char *a = "angus";
char *b,*x;
b = malloc((strlen(a) * sizeof(*a)) + 1);
x = b;
if(b == NULL){
}
ret_val = str_rev(a,&b);
if(ret_val == FAILURE){
printf("\n String is not reversed! going to quit! \n");
free(b);
return FAILURE;
}
printf("\n b:%s \n",b);
free(b);
return SUCCESS;
}
I changed the code as above, as 'a' contains the string. hence a single pointer is enough to point to that location as no changes needs to be done. But even after this above change The contents in 's' are not getting copied to 'd'. And i'm getting a seg fault after printing "printf("\n b:%s \n",b);" .
In addition to memory allocation problem also second problem in your code:
First
after your copy loop:
while(count > 0){
**d++ = **s--;count--;
}
You do not terminate d string ny null
add
**d= '\0';
Second: after your first loop
while(**s != '\0'){
**s++;count++;
}
You copy from Null do destination first char become '\0' then how you can print using %s
you should decrements s to point back to last char instead of null char. by --s.
Third
memory allocation do like:
char *a = "angus";
char *b;
b = malloc(strlen(a)*sizeof(*a) + 1);
don't forget to free() memory for b
Four
Next is you forgot to return return SUCCESS; from str_rev()
Firth
you are passing pointer to pointer that change the b and 's' value it self in calling function. When you call with &s and modifies s then no string points to "angus" string.
Do like below I coded you logic using single pointer instead.
int str_rev(char *s, char *d){
int count = 0;
if(s == NULL || d == NULL){
printf("\n Invalid address received! \n");
return FAILURE;
}
else{
while(*s != '\0'){
s++;
count++;
}
count;
--s;
while(count > 0){
*d = *s;
// printf("\n %c %c", *d, *s);
d++ ;
s--;
count--;
}
*d = '\0';
}
return SUCCESS;
}
in main just call as:
ret_val = str_rev(a, b);
EDIT: Second Code
I notice you are not happy with my suggestion to use single pointer for both!
Well in your second (EDIT) there are some repeating errors:
(1): From function str_rev() your again forgot to return SUCCESS.
(2): Your syntax for str_rcv function is int str_rev(char *s, char **d), first argument is char* but in main() you call it like ret_val = str_rev(&a,&b); that is wrong incompatibly pointer assignment. you should call like:
ret_val = str_rev(a, &b);
(3): IMPORTANT FOR YOU: In second argument you are passing &b Where as in str_rev() function you are updating d pointer hence updating b to which you allocated memory through malloc(), You can't do that!
This will cause an error also: memory clobbered before allocated block
You should rectify your code to call like this: (read comments please)
b = malloc((strlen(a) * sizeof(*a)) + 1);
if(b == NULL){
return FAILURE; // added this line too
}
char* x = b; // first assign b to x, notice x and b are of
// same type char*
ret_val = str_rev(a,&x); // know pass &x instead of &b
(4): although my previous code also working get new version too:
#define SUCCESS 0
#define FAILURE -1
int str_rev(char *s, char **d){
int count = 0;
if(s == NULL || d == NULL){
printf("\n Invalid address received! \n");
return FAILURE;
}
else{
while(*s != '\0'){
s++;count++;
}
s--;
while(count > 0){
*(*d)++ = *s--;
printf("\n *s:%c And **d: %c\n",*(s+1), *((*d)-1)); // for bug finding
// because s decremented and d incremented
count--;
}
**d = '\0';
return 0;
}
}
the main function():
int main(){
int ret_val = SUCCESS;
char *a = "angus";
char *b;
b = malloc((strlen(a) * sizeof(*a)) + 1);
if(b == NULL){
return -1;
}
char* x = b;
ret_val = str_rev(a,&x);
if(ret_val == FAILURE){
printf("\n String is not reversed! going to quit! \n");
free(b);
return FAILURE;
}
printf("\n b:%s \n",b);
free(b);
return SUCCESS;
}
Its working Output is:
*s:s And **d: s
*s:u And **d: u
*s:g And **d: g
*s:n And **d: n
*s:a And **d: a
b:sugna
Here your running code at Codpad
Here:
**s++
you are incrementing the char ** s. This alters it to point to the next char * which is not meaningful in your program.
Because of operator precedence, **s++ is the same as (*(*(s++)). Which is to say, it returns the value of the char pointed to by the char * pointed to by s, and as a side-effect increments s to point to the 'next' char * (which isn't well-defined because you do not have an array of char *s).
A typical idiom in C string manipulation is *p++, which is the same as (*(p++)). This returns the value of the char pointed to by p and as a side effect sets p to point to the next char, which would be the next character in the string. To do the same with a char ** one must write *(*p)++, or more explicitly (*((*p)++)).
Also, it is not necessary to use char **s to reverse a string; it can be done with only char *s.
In this line
b = malloc(sizeof(b));
sizeof(b) is just the size of a pointer and that is not ehough to fit a whole string.
Either pass the size you want to malloc
b = malloc(42);
b = malloc(strlen(a) + 1);
or change b into an array instead of a pointer
char b[42];
Other than that, I would highly recommend learing to use tools like gdb or valgrind to debug these segmentation faults. At the least they will tell you what line is segfaulting and just that will help a lot.
Change ret = str_rev(&a,&b); to ret_val = str_rev(&a,&b);
Please find a reworked function as below
int str_rev(char **sinp, char **dout){
int count = 0;
char *s = *sinp; // Dereference the starting address of source
char *d = *dout; // Dereference the starting address of destination
if(s == NULL || d == NULL){
printf("\n Invalid address received! \n");
return FAILURE;
}
else{
while(*s != '\0'){
*s++;count++;
}
s--; // Requires a decrement as it is pointing to NULL
while(count > 0){
*d++ = *s--;
count--;
}
}
*d = '\0'; // Need a NULL terminator to convert it to string
return SUCCESS; // Requires a return as all branches of function should return values
}
char str[] = "hello";
char *foo = foo;
*foo++ is the equivalent to *(foo++), not (*foo)++. foo++ causes foo to point to the next char.
char str[] = "hello";
char *foo = str;
char **bar = &foo;
**bar++ is the equivalent to **(bar++);, not (**bar)++. bar++ causes bar to point to the next char *... Do you see a problem?
(*bar)++ causes foo to point to the next char. consider what you'd be doing to your caller's a and b variables in ret_val = str_rev(&a,&b);, (*s)++; and (*d)++.
Related
I keep getting segmentation fault when i try and compile this. Do i need a check possibly for even and odd? I know it means im trying to get memory that i dont have but im not sure where im making the mistake. This is C also.
#include<stdio.h>
int main()
{
char str[41], even[21], odd[21], *p, *pstr, *e, *o;
printf("Enter a string (40 characters maximum):");
scanf("%s", str);
*p=str[0];
*pstr=str[0];
for(*p=even[0]; *p != '\0';p++){
if((p-pstr) % 2 == 0){
*e=*p;
e++;
} else{
*o=*p;
o++;
}
}
*o = '\0';
*e = '\0';
printf("The even string is:%s", even);
printf("The odd string is:%s", odd);
return 0;
}
There is some confusion regarding the initialization of pointers in your code:
*p = str[0] copies the first character from str to the address pointed to by p, which is uninitialized, hence causes undefined behavior.
you should instead initialize the value of p to the address of str[0]:
p = &str[0];
which can be simplified as
p = str;
Here is a corrected version:
#include <stdio.h>
int main(void) {
char str[41], even[21], odd[21], *p, *pstr, *e, *o;
printf("Enter a string (40 characters maximum):");
if (scanf("%40s", str) == 1) {
e = even;
o = odd;
for (p = pstr = str; *p != '\0'; p++) {
if ((p - pstr) % 2 == 0) {
*e = *p;
e++;
} else {
*o = *p;
o++;
}
}
*o = '\0';
*e = '\0';
printf("The even string is: %s\n", even);
printf("The odd string is: %s\n", odd);
}
return 0;
}
p has no allocated memory, you can set p = str but not copy the char in str[0] to a random memory address, since p never allocated some memory where it points to.
I am doing an exercise for fun from K and R C programming book. The program is for finding the longest line from a set of lines entered by the user and then prints it.
Inputs:
This is a test
This is another long test
this is another long testthis is another long test
Observation:
It runs fine for the first two inputs but fails for the larger string (3rd input)
Errors:
Error in `./longest': realloc(): invalid next size: 0x000000000246e010 ***
Error in `./longest': malloc(): memory corruption (fast): 0x000000000246e030 ***
My efforts:
I have been trying to debug this since 2 days (rubber duck debugging) but the logic seems fine. GDB points to the realloc call in the _getline function and shows a huge backtrace with glibc.so memory allocation calls at the top.
Here is what I have written (partially, some part is taken from the book directly):-
#include <stdio.h>
#include <stdlib.h>
int MAXLINE = 10;
int INCREMENT = 10;
char* line = NULL, *longest = NULL;
void _memcleanup(){
free(line);
free(longest);
}
void copy(char longest[], char line[]){
int i=0;
char* temp = realloc(longest,(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
longest = temp;
while((longest[i] = line[i]) != '\0'){
++i;
}
}
int _getline(char s[]){
int i,c;
for(i=0; ((c=getchar())!=EOF && c!='\n'); i++){
if(i == MAXLINE - 1){
char* temp = realloc(s,(MAXLINE + INCREMENT)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
s= temp;
MAXLINE += INCREMENT;
}
s[i] = c;
}
if(c == '\n'){
s[i++] = c;
}
s[i]= '\0';
return i;
}
int main(){
int max=0, len;
line = malloc(MAXLINE*sizeof(char));
longest = malloc(MAXLINE*sizeof(char));
while((len = _getline(line)) > 0){
printf("%d%d", len, MAXLINE);
if(len > max){
max = len;
copy(longest, line);
}
}
if(max>0){
printf("%s",longest);
}
_memcleanup();
return 0;
}
You´re reallocating on copied addresses (because parameters).
A parameter in C is a copy of the original value everytime; in case of
a pointer it will point to the same location but the address itself is copied.
realloc resizes the buffer asociated with the address, everything fine so far.
But it can relocate the whole thing and assign a completely new address,
and this new address (if it happens) will be lost after the function returns to main.
Use a double pointer:
Pass a char **s instead of char *s (==char s[]) as formal parameter,
pass &xyz intead of xyz as actual value, and inside the function,
use *xyz and **xyz (or (*xyz)[index]) for address and value.
Other things:
Global variables are ugly (and confusing when named same as parameters),
multiplying with sizeof(char) is nonsense because it´s be 1 everytime,
and names in capitals should be used for #define´s rather than variables.
The double pointer alone, isn't the solution to your problems. You have 2 primary issues. You can see them by entering your strings as a string of characters and will notice you problem occurs when you pass the 20th character. (e.g. 01234567890123456789)
You have declared both line and longest globally. So while you can rewrite _getline (char **s), you can also simply update line at the end of _getline with memcpy (include string.h). For example:
memcpy (line, s, (size_t)i);
return i;
}
That cures your _getline issue. Issue two is fairly straight forward. You are not null-terminating longest in copy. (your choice of arguments with the same name as the globals presents challenges as well) Including the following fixes copy:
++i;
}
longest[i] = '\0';
}
If you incorporate both changes, then I believe you will find you routine works. You can then rewite _getline (char **s) and pass &line as another exercise. For example, you can rewrite _getline as:
int
_getline (char **s) {
int i, c;
for (i = 0; ((c = getchar ()) != EOF && c != '\n'); i++) {
if (i == MAXLINE - 1) {
char *temp = realloc (*s, (MAXLINE + INCREMENT) * sizeof (char));
if (temp == NULL) {
printf ("%s", "Unable to allocate memory");
_memcleanup ();
exit (1);
}
*s = temp;
MAXLINE += INCREMENT;
}
(*s)[i] = c;
}
if (c == '\n') {
(*s)[i++] = c;
}
(*s)[i] = '\0';
return i;
}
And then modify your call in main to:
while ((len = _getline (&line)) > 0) {
I am trying to read in from stdin (passing in value from a file). I am reading each character from the string and storing it into a dynamically allocated string pointer. When needed I realloc the memory. I am trying to get as many characters as possible. Though I can limit it to 100,000 chars. But the realloc fails after some iteration. But if I specify a chunk size big, say 1048567 during the first initialization in malloc, I am able to read the string completely. Why is this?
Below is my program:
#include <stdio.h>
#include <stdlib.h>
int display_mem_alloc_error();
enum {
CHUNK_SIZE = 31 //31 fails. But 1048567 passes.
};
int display_mem_alloc_error() {
fprintf(stderr, "\nError allocating memory");
exit(1);
}
int main(int argc, char **argv) {
int numStr; //number of input strings
int curSize = CHUNK_SIZE; //currently allocated chunk size
int i = 0; //counter
int len = 0; //length of the current string
int c; //will contain a character
char *str = NULL; //will contain the input string
char *str_cp = NULL; //will point to str
char *str_tmp = NULL; //used for realloc
str = malloc(sizeof(*str) * CHUNK_SIZE);
if (str == NULL) {
display_mem_alloc_error();
}
str_cp = str; //store the reference to the allocated memory
scanf("%d\n", &numStr); //get the number of input strings
while (i != numStr) {
if (i >= 1) { //reset
str = str_cp;
len = 0;
curSize = CHUNK_SIZE;
}
c = getchar();
while (c != '\n' && c != '\r') {
*str = (char *) c;
//printf("\nlen: %d -> *str: %c", len, *str);
str = str + 1;
len = len + 1;
*str = '\0';
c = getchar();
if (curSize / len == 1) {
curSize = curSize + CHUNK_SIZE;
//printf("\nlen: %d", len);
printf("\n%d \n", curSize); //NB: If I comment this then the program simply exits. No message is displayed.
str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
if (str_tmp == NULL) {
display_mem_alloc_error();
}
//printf("\nstr_tmp: %d", str_tmp);
//printf("\nstr: %d", str);
//printf("\nstr_cp: %d\n", str_cp);
str_cp = str_tmp;
str_tmp = NULL;
}
}
i = i + 1;
printf("\nlen: %d", len);
//printf("\nEntered string: %s\n", str_cp);
}
str = str_cp;
free(str_cp);
free(str);
str_cp = NULL;
str = NULL;
return 0;
}
Thanks.
When you realloc
str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
if (str_tmp == NULL) {
display_mem_alloc_error();
}
//printf("\nstr_tmp: %d", str_tmp);
//printf("\nstr: %d", str);
//printf("\nstr_cp: %d\n", str_cp);
str_cp = str_tmp;
str_tmp = NULL;
you let str_cp point to the new block of memory, but str still points into the old, now freed block. Thus when you access what str points to in the next iteration, you invoke undefined behaviour.
You need to save the offset of str with respect to str_cp, and after the reallocation, letstr point into the new block at its old offset.
And *str = (char *) c; is wrong, although there is a nonzero chance of it being functionally equivalent to the correct *str = c;.
*str = (char *) c;
This line is wrong.
str is a pointer to char and *str is a char but you are assigning a pointer to char to a char. This cannot be done in C.
Moreover:
scanf("%d\n", &numStr);
The \n in scanf call probably does not what you expect:
http://c-faq.com/stdio/scanfhang.html
And also:
str = str_cp;
free(str_cp);
free(str);
You have a double free here. After the assignment str and str_cp will have the same value so doing:
free(str_cp);
free(str);
is as if you do:
free(str);
free(str);
which is undefined behavior (you cannot free twice).
This is my code:
#include <stdio.h>
#include <stdlib.h>
void getinfo(unsigned int a, unsigned int b, char **s);
int main(){
unsigned int len_max = 8;
unsigned int current_size = 0;
char *pStr = malloc(len_max);
if(pStr == NULL){
perror("\nMemory allocation\n");
return EXIT_FAILURE;
}
current_size = len_max;
printf("Inserisci hostname: ");
getinfo(len_max, current_size, &pStr);
printf("\nLa stringa inserita è: %s\n", pStr);
free(pStr);
return EXIT_SUCCESS;
}
void getinfo(unsigned int a, unsigned int b, char **pStr){
unsigned int i = 0;
char c = EOF;
while((c = getchar()) != '\n'){
*pStr[i++] = (char)c;
if(i == b){
b = i+a;
if((*pStr = realloc(*pStr, b)) == NULL){
perror("\nMemory allocation error\n");
exit(EXIT_FAILURE);
}
}
}
*pStr[i]='\0';
}
When i execute this code i got a segmentation fault when i press enter (after i've wrote the string).
I'm sure the problem is into the function (probably the problem is the *s pointer) but i don't know how to correct it...
You have a precedence problem. You need to use
(*s)[i++] = ...
instead of
*s[i++] = ...
Similarly you need
(*s)[i]='\0';
When you write *s[i] you are indexing s. But you want to index *s, and hence require the parentheses.
I've not checked the rest of your code, but I hope this helps you on your way to debugging the rest of it, if indeed there are more errors.
The problem is with *s[i++] = (char)c; try turning it into (*s)[i++] = (char)c; with the parenthesis around the *s. As well as (*s)[i] = '\0'.
The code says at many places "invalid indirection".Please help.
int main()
{
char *s1,*s2,*position;
printf("Enter string:\n");
gets(s1);
printf("Enter word to find:\n");
gets(s2);
*position=ststr(*s1,*s1);
if(*position)
printf("word is found at %c loc\n",*position);
else
printf("word not found");
getch();
return 0;
}
char *strstr(char *s1,char *s2)
{
int flag=1;
char i,j;
for(i=0; ;i++)
{
if(*s1[i]==*s2[0])
for(j=i;*s2;j++)
{
if(*s1[j]!=*s2[j])
flag=0;
}
}
if(flag)
return i;
else
return 0;
}
First, s1 and s2 in main have not been initialized to point anywhere meaningful. Either declare them as static arrays, or allocate memory to them at runtime using malloc() or calloc():
#define SIZE 20 // or some number big enough to hold your input
...
char s1[SIZE], s2[SIZE], *position; // s1 and s2 declared statically
Second, NEVER NEVER NEVER NEVER NEVER use gets(); it will introduce a point of failure in your program. Use fgets() instead:
if (fgets(s1, sizeof s1, stdin) != NULL)
// process s1
else
// check for EOF or error on read
EDIT
And like everyone else has pointed out, your comparison in the strstr() function needs to be either
*s1 == *s2
or
s1[i] == s2[i]
but first you need to deal with allocating your buffers in main properly.
One of the problems I'm noticing is whenever you do *s1[j]. The asterisk is dereferencing the array, and so is the [] notation.
s[i] really means *(s + i), so you don't have to dereference it again. The way you have it would read **(s + i), and since it's a single pointer you can't do that.
if(*s1[i]==*s2[0])
is such an example where my gcc complains:
error: invalid type argument of ‘unary *’ (have ‘int’)
if s1 is a pointer to char, s1[i] is a char. So you can't dereference it any more (with the *), i.e. s1[i] does not point to anything any more.
Try
if(s1[i]==s2[0])
instead.
You should also change the return value of strstr: you return an integer where you declare to return a pointer to a character. So try returning s1+i instead.
This here:
for(j=i;*s2;j++)
probably does not what you want. You're not advancing the pointer s2 anywhere in the loop, in fact you're just testing whether s2[0] (which is the same as *s2) is zero for each iteration. If s2 isn't the empty string, this loop will never terminate.
#include "stdio.h"
char *strstr(char *str, char *substr)
{
int len = strlen(substr);
char *ref = substr;
while(*str && *ref)
{
if (*str++ == *ref)
{
ref++;
}
if(!*ref)
{
return (str - len);
}
if (len == (ref - substr))
{
ref = substr;
}
}
return NULL;
}
int main(int argc, char *argv[])
{
printf("%s \n", strstr("TEST IS NOT DONE", "IS NOT"));
}
if(*s1[j]!=*s2[j])
*s1 means "the character where s1 is pointing".
s1[j] means "*(s1+j)" or "the character j positions after where s1 is pointing"
You have to use one or the other; not both.
#include <stdio.h>
char* my_strstr(char *s2, char *s1)
{
int i, j;
int flag = 0;
if ((s2 == NULL || s1 == NULL)) return NULL;
for( i = 0; s2[i] != '\0'; i++)
{
if (s2[i] == s1[0])
{
for (j = i; ; j++)
{
if (s1[j-i] == '\0'){ flag = 1; break;}
if (s2[j] == s1[j-i]) continue;
else break;
}
}
if (flag == 1) break;
}
if (flag) return (s2+i);
else return NULL;
}
int main()
{
char s2[] = "This is the statement";
char s1[] = "the";
char *temp;
temp = my_strstr(s2,s1);
printf("%s\n",temp);
return 0;
}