As the title says. I don't Understand why this code gives me segfault!
#include <stdio.h>
void cp(char s[], char d[]);
int main () {
char s[100] = "hi there how are you";
char d[100];
cp(s, d);
printf("%s\n++++++++\n%s\n", s, d);
return 0;
}
void cp(char s[], char d[]) {
int i, p = 0;
while (s[i] != '\0') {
d[i] = s[i];
++i;
++p;
}
}
I know the cp implementation is terrible! I wrote it like this just for fun, then the segfault happened.
In this line of code:
int i, p = 0;
you only initialize p, variable i is uninitialized, reading from it leads to UB.
Proper loop could be written like this:
for( size_t i = 0; ( d[i] = s[i] ) != 0; ++i );
(it will also copy null-terminator which you would be missing if initialize i properly)
Another variant is classical C way:
void cp(const char *s, char *d)
{
while( *d++ = *s++ );
}
but usually in C target is the first parameter, not the second (for example strcpy())
You copy only while:
while (s[i] != '\0')
so '\0' isn't copied so when you run:
printf("%s\n++++++++\n%s\n", s, d);
you get a segfault.
Also i is uninitialised:
int i, p = 0;
using separate lines avoids this typo:
int i = 0;
int p = 0;
an uninitialised i can blow up:
d[i] = s[i];
causing a segfault.
Related
I was trying to write a program that reverses its input a line at a time. I thought I had done it successfully, however it sometimes doesn't give the desirable output (this happens when I put an input with a smaller length than the one I put previously). I am new to this and I was wondering what can I do to solve this issue.
Program:
#include <stdio.h>
#define MAXLINE 1000
void reverse(char o[], char l[]);
int mgetline(char line[]);
int main(void){
int len;
char line[MAXLINE];
char rev[MAXLINE];
while((len = mgetline(line)) > 0){
reverse(rev, line);
printf("%s\n",rev);
}
return 0;
}
int mgetline(char s[])
{
int c,i;
for(i = 0; ((c=getchar())!=EOF) && (c!='\n'); ++i)
s[i] = c;
if (c == '\n')
{
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
void reverse(char revi[], char liner[])
{
int i, c, j;
for(i=0;liner[i]!='\0';++i)
;
--i;
if(liner[i]=='\n')
--i;
for(j=0; j<=i ; ++j){
c = i - j;
revi[j] = liner[c];
}
--j;
}
Since you not terminating the revi string at the end, therefore it will print the leftout characters from the previous result if the new input is smaller. Fix it by adding this
revi[j] = '\0';
at the end of the reverse function and delete that last --j;.
The function reverse does not build a string that is it does not append the terminating zero '\0' to the result string.
The second parameter of the function should have the qualifier const because it is not changed in the function.
As all standard C string functions this function should return pointer to the result string.
And it is better to name the function like reverse_copy instead of reverse because the name reverse is usually used when a container is reversed "in place".
It can look the following way
char * reverse_copy( char revi[], const char liner[] )
{
size_t n = 0;
while ( liner[n] ) ++n;
if ( n != 0 && liner[n-1] == '\n' ) --n;
size_t i = 0;
while ( n != 0 ) revi[i++] = liner[--n];
revi[i] = '\0';
return revi;
}
I tried following two ways to reverse a string in C using char pointers:
Option 1:
void stringreverse(char *s){
int n = stringlength(s) - 2;
while(*s != '\0'){
char c = *s;
*s = *(s+n);
*(s+n) = c;
s++;n--;
}
}
Option 2:
void stringreverse(char *s){
char *p = s + stringlength(s) - 2;
while(*s != '\0'){
char c = *s;
*s = *p;
*p = c;
s++,p--;
}
}
None of the above works. Hints on why?
The problem is that your code reverses the string and then reverse it again, because your loop goes from 0 to len (when *s==\0), it should stop at (len-1)/2
You should try this :
void stringreverse(char* s){
int len = strlen(s)-1;
int i;
for(i=0;i<len/2;i++){
char tmp = s[i];
s[i] = s[len-i];
s[len-i]=tmp;
}
}
To reverse the string you should swap the chars between the beginning and the end of the string until they meet in the middle, the way you did will reverse it and then reverse it again to the original string. Also there is strlen in standard C. Anyway using your definition of stringlength, it should be:
void stringreverse(char *s){
int n = stringlength(s) - 2;
int i;
while(i = 0; i < n / 2; i++) {
char c = s[i];
s[i] = s[n-i];
s[n-i] = c;
}
}
complete working sample using pointers:
#include <stdio.h>
void reverse(char *p){
char c;
char* q = p;
while (*q) q++;
q--; // point to the end
while (p < q){
c = *p;
*p++ = *q;
*q-- = c;
}
}
int main(){
char s[] = "DCBA";
reverse(s);
printf("%s\n", s); // ABCD
}
p: points to start of string.
q: points to the end of string.
then swap their contents.
simple and easy.
I am playing with pointers in the K&R book and I wrote this program that swaps integers and measures the length of a string with a pointer. The first part works but my string length function does nothing. The program compiles and runs the first part and then the program stops responding.
#include <stdio.h>
extern int a2 = 4;
extern int b2 = 5;
void swap(int *px, int *py);
int strlen2(char *s);
//int printLabel(char *thelabel, char newliner);
//int printLabel(char *thelabel, char newliner)
//{
// int stringlength1=(strlen2(thelabel));
// return stringlength1;
//}
void swap(int *px, int *py) /* interchange *px and *py */
{
int temp;
temp = *px;
*px = *py;
*py = temp;
}
int strlen2(char *s)
{
int n;
for (n = 0; *s != '\0', s++;)
n++;
return n;
}
int main()
{
int a=4;
int b=5;
char newliner = '\n';
swap(&a,&b);
swap(&a2,&b2);
printf("%d",a);
printf("%c",newliner);
printf("%d",b);
printf("%c",newliner);
printf("%d",a2);
printf("%c",newliner);
printf("%d",b2);
printf("%c",newliner);
char sumstring[]="boo";
char *labelPtr;
labelPtr = sumstring;
int length = strlen2(labelPtr);
printf("%d",length);
return 0;
}
The problem is that this:
for (n = 0; *s != '\0', s++;)
is a semi-infinite loop. It checks for the terminating NUL, but then it ignores the result of that comparison and increements s, continuing the loop if it is non-null. Once it gets past the end of the string, the result is undefined behavior, but its likely to either loop forever or crash.
You probably meant
for (n = 0; *s != '\0'; s++)
In the for loop, the second expression is usually a condition, in your case *s != '\0'.
The 3rd expression is the increment, where you are supposed to increment the s pointer.
This is working fine:
int strlen2(char *s)
{
int n;
for (n = 0; *s != '\0'; s++)
n++;
return n;
}
Replace your code with the following:
int strlen2(char *s)
{
int n = 0;
while(s[n] != '\0')
++n;
return n;
}
looks like a typo in the code. shouldn't this line be:
for (n = 0; *s != '\0'; s++)
instead of
for (n = 0; *s != '\0', s++;)
In this for statmenet
for (n = 0; *s != '\0', s++;)
in the condition part there is used the comma operator
*s != '\0', s++
Its results is the value of the last subexpression that is of s++. As pointer s is not equal to 0 then you get at least very long sycle.
I think you meant instead
for (n = 0; *s != '\0'; s++ )
I am new with pointers on C and I am trying to write a function like strcat() but without using it. I developed the following function:
char cat(char *a, char *b) {
int i=0,cont=0,h=strlen(a)+strlen(b);
char c[h]; //new string containing the 2 strings (a and b)
for(i;i<strlen(a);++i) {
c[i] = *(a+i); //now c contains a
}
int j = i;
for(j;j<strlen(b);++j) {
c[j] = *(b+cont); //now c contains a + b
cont++;
}
return c; // I return c
}
And this is how I call the function:
printf("\Concatenazione: %c", cat(A,B));
It is now working because the final result is a weird character. How could I fix the function? Here there's the full main.
char * strcat(char *dest, const char *src)
{
int i;
int j;
for (i = 0; dest[i] != '\0'; i++);
for (j = 0; src[j] != '\0'; j++) {
dest[i+j] = src[j];
}
dest[i+j] = '\0';
return dest;
}
From your implementation it appears that your version of strcat is not compatible with the standard one, because you are looking to allocate memory for the result, rather than expecting the caller to provide you with enough memory to fit the result of concatenation.
There are several issues with your code:
You need to return char*, not char
You need to allocate memory dynamically with malloc; you cannot return a locally allocated array.
You need to add 1 for the null terminator
You need to write the null terminator into the result
You can take both parameters as const char*
You can simplify your function by using pointers instead of indexes, but that part is optional.
Here is how you can do the fixes:
char *cat(const char *a, const char *b) {
int i=0,cont=0,h=strlen(a)+strlen(b);
char *c = malloc(h+1);
// your implementation goes here
c[cont] = '\0';
return c;
}
You are returning a POINTER to the string, not the actual string itself. You need to change the return type to something like "char *" (or something equivalent). You also need to make sure to null terminate the string (append a '\0') for it to print correctly.
Taking my own advice (and also finding the other bug, which is the fact that the second for loop isn't looping over the correct indices), you end up with the following program:
#include <stdio.h>
char *cat(char *a, char *b) {
int i = 0, j = 0;
int cont = 0;
int h = strlen(a) + strlen(b) + 1;
char *result = (char*)malloc(h * sizeof(char));
for(i = 0; i < strlen(a); i++) {
result[i] = a[i];
}
for(j = i; j < strlen(b)+ strlen(a); j++) {
result[j] = b[cont++];
}
// append null character
result[h - 1] = '\0';
return result;
}
int main() {
const char *firstString = "Test First String. ";
const char *secondString = "Another String Here.";
char *combined = cat(firstString, secondString);
printf("%s", combined);
free(combined);
return 0;
}
c is a local variable. It only exists inside the function cat. You should use malloc.
instead of
char c[h];
use
char *c = malloc(h);
Also, you should add the null byte at the end. Remember, the strings in C are null-ended.
h = strlen(a) + strlen(b) + 1;
and at the end:
c[h - 1] = '\0';
The signature of cat should be char *cat(char *a, char *b);
You will get an error of
expected constant expression
for the code line char c[h];. Instead you should be using malloc to allocate any dynamic memory at run-time like::
char* c ;
c = malloc( h + 1 ) ; // +1 for the terminating null char
// do stuff
free( c ) ;
Your corrected code::
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include <stdlib.h>
char* cat(char *a, char *b) {
int i=0,cont=0,h=strlen(a)+strlen(b), j;
char *c;
c = malloc( h+1 ) ;
for(i;i<strlen(a);++i) {
c[i] = *(a+i);
}
j = 0 ;
for(j;j<strlen(b);++j) {
c[i] = *(b+cont);
i++ ;
cont++;
}
c[i] = 0 ;
return c;
}
int main() {
char A[1000],B[1000];
char * a ;
printf("Inserisci la stringa 1: \n");
gets(A);
printf("Inserisci la stringa 2: \n");
gets(B);
a = cat(A,B) ;
printf("\nConcatenazione: %s", a);
free(a) ;
getch();
return 0;
}
/* squeeze: delete all c from s */
void squeeze(char s[], int c)
{
int i, j;
for (i = j = 0; s[i] != '\0'; i++)
if (s[i] != c)
s[j++] = s[i];
s[j] = '\0';
}
int main(void)
{
squeeze("squeeze", 'z');
return 0;
}
I compiled it with gcc and ran it, and got a segmentation fault as a result.
Anything wrong with this example?
thanks to men,i have just made a usual mistake.
Your example shows that you're trying to apply squeeze() to a string literal ("squueze"). This is not correct, since string literals are not always modifiable so it's invalid to try
to modify them. You need to call it with a character array:
#include <stdlib.h>
int main(void)
{
char test[] = "squeeze";
squeeze(test, 'z');
return EXIT_SUCCESS;
}