Why char[] work,but char * doesn't [duplicate] - c

This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 7 years ago.
code1:
int main()
{
char tmp[20] = "1.04";
printf("float str is %s\n",tmp);
delcharPoint(tmp);
printf("%s\n",tmp);
}
void delcharPoint(char *pStr)
{
char *pTmp = pStr;
int flag_0 = 0;
printf("*pTmp = %s\n",pTmp);
printf("*pTmp = %s\n",pTmp);
if(*pStr == '0')
{
pStr++;
flag_0 = 1;
}
while(*pStr != '\0')
{
if(*pStr != '.')
{
*pTmp++ = *pStr;
pStr++;
}
else
{
pStr++;
if(flag_0 ==1 && *pStr == '0')
{
pStr++;
}
}
}
*pTmp = '\0';
}
This code worked well and it print:
float str is 1.04
*pTmp = 1.04
*pTmp = 1.04
104
Code2:
int main()
{
char *tmp = "1.04";
printf("float str is %s\n",tmp);
delcharPoint(tmp);
printf("%s\n",tmp);
}
void delcharPoint(char *pStr)
{
char *pTmp = pStr;
int flag_0 = 0;
printf("*pTmp = %s\n",pTmp);
printf("*pTmp = %s\n",pTmp);
if(*pStr == '0')
{
pStr++;
flag_0 = 1;
}
while(*pStr != '\0')
{
if(*pStr != '.')
{
*pTmp++ = *pStr;
pStr++;
}
else
{
pStr++;
if(flag_0 ==1 && *pStr == '0')
{
pStr++;
}
}
}
*pTmp = '\0';
}
This code doesn't work,it print:
float str is 1.04
*pTmp = 1.04
*pTmp = 1.04
Segmentation fault
The difference between two codes only is I use char[] in code1 and char * in code2.I have searched the difference between char[] and char *.But I still don't what cause the difference between these code.

Here:
char *tmp = "1.04";
"1.04" is a string literal and string literals are immutable, meaning that it cannot be changed. Attempting to do so results in Undefined Behavior.
On the other hand,
char tmp[20] = "1.04";
creates a char array, copies "1.04" into it. Modifying the contents of an array is legal.

Related

exception in for loop? [duplicate]

This question already has answers here:
EXC_BAD_ACCESS when using strcpy()?
(3 answers)
Why can I not modify a string literal in c?
(1 answer)
Closed 2 years ago.
Why my code returns:
Exception: EXC_BAD_ACCESS (code=2, address=0x10d637fa2)
in the first time it enters the for loops?
void unAnnoyWord(char *str) {
char *out = str, mostAnnoying = 'a';
do
{
if (*str != mostAnnoying)
{
*out = *str;
}
} while (*str++);
}
char *str = "hakuna matata";
unAnnoyWord(str);
Perhaps this is what you want:
#include <stdio.h>
void unAnnoyWord(char *str) {
char *out = str, mostAnnoying = 'a';
do {
if (*str != mostAnnoying) {
*out++ = *str;
}
} while (*str++);
}
void main() {
char str[] = "hakuna matata";
char *sstr = str;
printf("%s\n",sstr);
unAnnoyWord(str);
printf("%s\n",sstr);
}
Resulting in:
hakuna matata
hkun mtt

How to return a pointer to a string in C [duplicate]

This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 4 years ago.
I tried to develop a function which take a string reverse letters and return pointer to string.
char *reverseStr(char s[])
{
printf("Initial string is: %s\n", s);
int cCounter = 0;
char *result = malloc(20);
while(*s != '\0')
{
cCounter++;
s++;
}
printf("String contains %d symbols\n", cCounter);
int begin = cCounter;
for(; cCounter >= 0; cCounter--)
{
result[begin - cCounter] = *s;
s--;
}
result[13] = '\0';
return result;
}
in main function I invoke the function and tried to print the result in this way:
int main()
{
char testStr[] = "Hello world!";
char *pTestStr;
puts("----------------------------------");
puts("Input a string:");
pTestStr = reverseStr(testStr);
printf("%s\n", pTestStr);
free(pTestStr);
return 0;
}
but the result is unexpected, there is no reverse string.
What is my fault?
There are multiple mistakes in the shared code, primarily -
s++; move the pointer till '\0'. It should be brought back 1 unit to
point to actual string by putting s--. Other wise the copied one will start with '\0' that will make it empty string.
Magic numbers 20 and 13. where in malloc() 1 + length of s should be
sufficient instead or 20. For 13 just move a unit ahead and put '\0'
However, using string.h library functions() this can be super easy. But I think you are doing it for learning purpose.
Therefore, Corrected code without using string.h lib function() should look like this:
char *reverseStr(char s[])
{
printf("Initial string is: %s\n", s);
int cCounter = 0;
while(*s != '\0')
{
cCounter++;
s++;
}
s--; //move pointer back to point actual string's last charecter
printf("String contains %d symbols\n", cCounter);
char *result = (char *) malloc(sizeof(char) * ( cCounter + 1 ));
if( result == NULL ) /*Check for failure. */
{
puts( "Can't allocate memory!" );
exit( 0 );
}
char *tempResult = result;
for (int begin = 0; begin < cCounter; begin++)
{
*tempResult = *s;
s--; tempResult++;
}
*tempResult = '\0';
//result[cCounter+1] = '\0';
return result;
}
Calling from main
int main()
{
char testStr[] = "Hello world!";
char *pTestStr;
puts("----------------------------------");
puts("Input a string:");
pTestStr = reverseStr(testStr);
printf("%s\n", pTestStr);
free(pTestStr);
}
Output
----------------------------------
Input a string:
Initial string is: Hello world!
String contains 12 symbols
!dlrow olleH
As per WhozCraig suggestion just by using pointer arithmetic only -
char *reverseStr(const char s[])
{
const char *end = s;
while (*end)
++end;
char *result = malloc((end - s) + 1), *beg = result;
if (result == NULL)
{
perror("Failed to allocate string buffer");
exit(EXIT_FAILURE);
}
while (end != s)
*beg++ = *--end;
*beg = 0;
return result;
}
Your code can be simplified using a string library function found in string.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverseStr(char s[])
{
printf("Initial string is: %s\n", s);
int cCounter = strlen(s);
char *result = malloc(cCounter + 1);
printf("String contains %d symbols\n", cCounter);
int begin = cCounter;
for(; cCounter > 0; cCounter--)
{
result[begin - cCounter] = s[cCounter - 1];
}
result[begin] = '\0';
return result;
}
int main()
{
char testStr[] = "Hello world!";
char *pTestStr;
puts("----------------------------------");
puts("Input a string:");
pTestStr = reverseStr(testStr);
printf("%s\n", pTestStr);
free(pTestStr);
return 0;
}
Output:
----------------------------------
Input a string:
Initial string is: Hello world!
String contains 12 symbols
!dlrow olleH

passing a char* as argument breaks program whereas char[] does not [duplicate]

This question already has answers here:
What is the difference between char s[] and char *s?
(14 answers)
Definitive List of Common Reasons for Segmentation Faults
(1 answer)
Closed 5 years ago.
I have the following code to split strings by tokens:
char **strToWordArray(char *str, const char *delimiter)
{
char **words;
int nwords = 1;
words = malloc(sizeof(*words) * (nwords + 1));
int w = 0;
int len = strlen(delimiter);
words[w++] = str;
while (*str)
{
if (strncmp(str, delimiter, len) == 0)
{
for (int i = 0; i < len; i++)
{
*(str++) = 0;
}
if (*str != 0) {
nwords++;
char **tmp = realloc(words, sizeof(*words) * (nwords + 1));
words = tmp;
words[w++] = str;
} else {
str--;
}
}
str++;
}
words[w] = NULL;
return words;
}
If I do this:
char str[] = "abc/def/foo/bar";
char **words=strToWordArray(str,"/");
then the program works just fine but if I do this:
char *str = "abc/def/foo/bar";
char **words=strToWordArray(str,"/");
then I get a segmentation fault.
Why is that? The program expects a char* as an argument then why does a char* argument crash the program?
Because the function contains:
*(str++) = 0;
which modifies the string that was passed to it. When you do:
char *str = "abc/def/foo/bar";
str points to a read-only string literal. See the section titled Attempting to modify a string literal in this question:
Definitive List of Common Reasons for Segmentation Faults

Removing all occurences of all charactesr from second string in first string

I have a small problem.
I have a function that takes in two parameters (two strings). For example:
String1 = "hello"
String2 = "leo"
I need to remove all characters from String2 in String1. In this case, my final result should be: "h". I need to incorporate pointers when doing this! I've got this code so far, but it's only remove "e" from "hello". I don't know why it's not working. If someone has a better or efficient way of doing this, please help!
void rmstr(char str1[], char str2[])
{
//Pointers to traverse two strings
char *p_str1 = &str1[0];
char *p_skip;
int length = (int)strlen(str2);
int i;
while(*p_str1 != '\0')
{
for (i = 0; i < length; i++)
{
if(*p_str1 == str2[i])
{
for(p_skip = p_str1; *p_skip == str2[i]; ++p_skip);
memcpy(p_str1, p_skip, &str1[strlen(str1)+1] - p_skip);
}
if(*p_str1 != '\0')
{
++p_str1;
}
}
}
}
char* rmstr(char *str1, char *str2, char *ans) {
char *p1 = str1;
char *p2 = str2;
char *res = ans;
while (*p1 != '\0') {
p2 = str2;
while (*p2 != '\0') {
if (*p1 == *p2) // A character in str1 is found inside str2
break;
p2++;
}
if (*p2 == '\0') { // No match found
*ans = *p1;
ans++;
}
p1++;
}
*ans = '\0';
return res;
}
Testing code:
int main(void) {
char str1[] = "hello";
char str2[] = "elo";
char ans[10];
printf(rmstr(str1, str2, ans));
return 0;
}
Well, this answer has less variables and maybe easier to read.
#include "stdio.h"
/* check if c belongs to the second str */
int char_belong_to_str(char c, char *str)
{
while(*str)
if (c == *str++)
return 1;
return 0;
}
void rmstr(char str1[], char str2[])
{
int result_len = 0; /* saves the result str len*/
char * p_new = str1;
while (*str1)
{
char c = *str1;
if (!char_belong_to_str(c, str2)) /* if not found in str2, save it*/
{
*(p_new + result_len) = c;
++result_len;
}
++str1;
}
*(p_new+result_len) = '\0';
printf("%s \n", p_new);
}
int main()
{
char p1[] = "hello";
char p2[] = "elo";
rmstr(p1, p2);
return 0;
}

Create a new string that will consist of common letters from other two strings

I'm new to C programming. I have a task to do.
User inputs two strings. What I need to do is to create a new string that will consist only from common letters of those two given strings.
For example:
if given:
str1 = "ABCDZ"
str2 = "ADXYZ"
the new string will look like: "ADZ".
I can't make it work. I think there must be a better (more simple) algorithm but I have waisted too much time for this one so I want to complete it .. need your help!
what I've done so far is this:
char* commonChars (char* str1, char* str2)
{
char *ptr, *qtr, *arr, *tmp, *ch1, *ch2;
int counter = 1;
ch1 = str1;
ch2 = str2;
arr = (char*) malloc ((strlen(str1)+strlen(str2)+1)*(sizeof(char))); //creating dynamic array
strcpy(arr, str1);
strcat(arr,str2);
for (ptr = arr; ptr < arr + strlen(arr); ptr++)
{
for (qtr = arr; qtr < arr + strlen(arr); qtr++) // count for each char how many times is appears
{
if (*qtr == *ptr && qtr != ptr)
{
counter++;
tmp = qtr;
}
}
if (counter > 1)
{
for (qtr = tmp; *qtr; qtr++) //removing duplicate characters
*(qtr) = *(qtr+1);
}
counter = 1;
}
sortArray(arr, strlen(arr)); // sorting the string in alphabetical order
qtr = arr;
for (ptr = arr; ptr < arr + strlen(arr); ptr++, ch1++, ch2++) //checking if a letter appears in both strings and if at least one of them doesn't contain this letter - remove it
{
for (qtr = ptr; *qtr; qtr++)
{
if (*qtr != *ch1 || *qtr != *ch2)
*qtr = *(qtr+1);
}
}
}
Don't know how to finish this code .. i would be thankful for any suggestion!
The output array cannot be longer that the shorter of the two input arrays.
You can use strchr().
char * common (const char *in1, const char *in2) {
char *out;
char *p;
if (strlen(in2) < strlen(in1)) {
const char *t = in2;
in2 = in1;
in1 = t;
}
out = malloc(strlen(in2)+1);
p = out;
while (*in1) {
if (strchr(in2, *in1)) *p++ = *in1;
++in1;
}
*p = '\0';
return out;
}
This has O(NxM) performance, where N and M are the lengths of the input strings. Because your input is alphabetical and unique, you can achieve O(N+M) worst case performance. You apply something that resembles a merge loop.
char * common_linear (const char *in1, const char *in2) {
char *out;
char *p;
if (strlen(in2) < strlen(in1)) {
const char *t = in2;
in2 = in1;
in1 = t;
}
out = malloc(strlen(in2)+1);
p = out;
while (*in1 && *in2) {
if (*in1 < *in2) {
++in1;
continue;
}
if (*in2 < *in1) {
++in2;
continue;
}
*p++ = *in1;
++in1;
++in2;
}
*p = '\0';
return out;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define min(x,y) ((x)<(y)? (x) : (y))
char* commonChars (const char *str1, const char *str2){
//str1, str2 : sorted(asc) and unique
char *ret, *p;
int len1, len2;
len1=strlen(str1);
len2=strlen(str2);
ret = p = malloc((min(len1, len2)+1)*sizeof(char));
while(*str1 && *str2){
if(*str1 < *str2){
++str1;
continue;
}
if(*str1 > *str2){
++str2;
continue;
}
*p++ = *str1++;
++str2;
}
*p ='\0';
return ret;
}
char *deleteChars(const char *str, const char *dellist){
//str, dellist : sorted(asc) and unique
char *ret, *p;
ret = p = malloc((strlen(str)+1)*sizeof(char));
while(*str && *dellist){
if(*str < *dellist){
*p++=*str++;
continue;
}
if(*str > *dellist){
++dellist;
continue;
}
++str;
++dellist;
}
if(!*dellist)
while(*str)
*p++=*str++;
*p ='\0';
return ret;
}
int main(void){
const char *str1 = "ABCDXYZ";
const char *str2 = "ABCDZ";
const char *str3 = "ADXYZ";
char *common2and3;
char *withoutcommon;
common2and3 = commonChars(str2, str3);
//printf("%s\n", common2and3);//ADZ
withoutcommon = deleteChars(str1, common2and3);
printf("%s\n", withoutcommon);//BCXY
free(common2and3);
free(withoutcommon);
return 0;
}
I will do something like this :
char* commonChars(char* str1, char* str2) {
char* ret = malloc(strlen(str1) * sizeof(char));
int i = j = k = 0;
for (; str1[i] != '\n'; i++, j++) {
if (str1[i] == str2[j]) {
ret[k] = str1[i];
k++;
}
}
ret[k] = '\0';
ret = realloc(ret, k);
return ret;
}
It's been a while i didn't do C, hope this is correct
You can use strpbrk() function, to do this job cleanly.
const char * strpbrk ( const char * str1, const char * str2 );
char * strpbrk ( char * str1, const char * str2 );
Locate characters in string
Returns a pointer to the first occurrence in str1 of any of the characters that are part of str2, or a null pointer if there are no matches.
The search does not include the terminating null-characters of either strings, but ends there.
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "ABCDZ";
char key[] = "ADXYZ";
char *newString = malloc(sizeof(str)+sizeof(key));
memset(newString, 0x00, sizeof(newString));
char * pch;
pch = strpbrk (str, key);
int i=0;
while (pch != NULL)
{
*(newString+i) = *pch;
pch = strpbrk (pch+1,key);
i++;
}
printf ("%s", newString);
return 0;
}
Sorry for the weird use of char arrays, was just trying to get it done fast. The idea behind the algorithm should be obvious, you can modify some of the types, loop ending conditions, remove the C++ elements, etc for your purposes. It's the idea behind the code that's important.
#include <queue>
#include <string>
#include <iostream>
using namespace std;
bool isCharPresent(char* str, char c) {
do {
if(c == *str) return true;
} while(*(str++));
return false;
}
int main ()
{
char str1[] = {'h', 'i', 't', 'h', 'e', 'r', 'e', '\0'};
char str2[] = {'a', 'h', 'i', '\0'};
string result = "";
char* charIt = &str1[0];
do {
if(isCharPresent(str2, *charIt))
result += *charIt;
} while(*(charIt++));
cout << result << endl; //hih is the result. Minor modifications if dupes are bad.
}
So i found the solution for my problem. Eventually I used another algorithm which, as turned out, is very similar to what #BLUEPIXY and #user315052 have suggested. Thanks everyone who tried to help! Very nice and useful web source!
Here is my code. Someone who'll find it useful can use it.
Note:
(1) str1 & str2 should be sorted alphabetically;
(2) each character should appear only once in each given strings;
char* commonChars (char* str1, char* str2)
{
char *ptr, *arr,*ch1, *ch2;
int counter = 0;
for (ch1 = str1; *ch1; ch1++)
{
for(ch2 = str2; *ch2; ch2++)
{
if (*ch1 == *ch2)
counter++;
}
}
arr = (char*)malloc ((counter+1) * sizeof(char));
ch1 = str1;
ch2 = str2;
ptr = arr;
for (ch1 = str1; *ch1; ch1++,ch2++)
{
while (*ch1 < *ch2)
{
ch1++;
}
while (*ch1 > *ch2)
{
ch2++;
}
if (*ch1 == *ch2)
{
*ptr = *ch1;
ptr++;
}
}
if (ptr = arr + counter)
*ptr = '\0';
return arr;
}

Resources