How to change arrays using void functions in C? - c

I just started trying to learn C a couple days ago by following along with the K&R book. I am not totally new to programming but I would say I am a novice. I've been doing mostly fine so far but I've been having a lot of trouble with array manipulation. In section 2.8 of the book, it defines a function called squeeze which takes in an array of characters and a single character and removes all instances of the single character from the array. I was confused at first because this was a void function.
#include <stdio.h>
void squeeze(char s[], char c);
int main(){
char s[] = "hello";
squeeze(s, 'l');
printf("%s\n", s);
}
void squeeze(char s[], char c){
int i, j;
for (i = j = 0; s[i] != '\0'; i++){
if (s[i] != c)
s[j] = s[i];
++j;
}
s[j] = '\0';
}
I implemented it into my own C program and, when I call the function in Main, it just prints my original array without altering it. I am reasonably sure that this is because I am not changing the array s[] with the Squeeze function before I call printf, but rather changing a copy of the array that isn't being used. I have researched using pointers to refer to arrays in C but I am still very confused on how to do that correctly, because no matter what I try I either get a segment error or the array is not changed. Can anyone help me understand how pointers and arrays work in this context?
EDIT: I did originally state the name of the parameter in the function prototype and declaration, but I made an error in copying it.

I am reasonably sure that this is because I am not changing the array s[] with the Squeeze function
Function prototype is ok:
void squeeze(char [], char c);
It's totally ok to parse array here, because array will decay to pointer anyway in the context of function parameter.
Your implementation wasn't correct, though:
You must provide the name of the parameter s
And must enclose your if statement properly, otherwise ++j; will be executed no matter whether the condition if (s[i] != c) is met or not.
Here's a guide to fix the two issues:
void squeeze(char s[], char c){ // <-- 1) must provide parameter name
int i, j;
for (i = j = 0; s[i] != '\0'; i++){
if (s[i] != c)
{ // <-- 2) must enclose if statement properly
s[j] = s[i];
++j;
}
}
s[j] = '\0';
}

you are changing the array with the squeeze function. But the squeeze function cant produce the output you needed beacause there is an implementation problem with the function.
#include <stdio.h>
void squeeze(char [], char c);
int main(){
char s[] = "hello";
squeeze(s, 'l');
printf("%s\n", s);
}
void squeeze(char s[], char c){
int i, j;
for (i = j = 0; s[i] != '\0'; i++){
if (s[i] != c)
s[j++] = s[i];
}
s[j] = '\0';
}
This one will produce the output you needed. Because in the case of if statement If you not gave any curly brackets The immediate line to the if loop will be taken as in the loop.
So in the case of
if (s[i] != c)
s[j] = s[i];
++j;
The ++j wont taken as in the loop. If you want to add ++j to loop. Then use the following code.
if (s[i] != c){
s[j] = s[i];
++j;
}

All are false in the internet, you should reassign the new variable
void squeeze(char s[],char c) {
printf("s=%s\n",s);
int i, j;
char new_s[20];
for (i = j = 0; s[i] != '\0'; i++)
{
if (s[i] != c)
{
new_s[j] = s[i];
j++; //这里加了一但是 s[j] 没有赋值,下一个循环时才赋值。。
//而最后一次没有下一个循环,所以s[j] 还没有赋值
}
}
printf("s=%s\n",new_s);
}

Related

Why am I getting a Seg-Fa

So I apologize for the general question. I haven't been able to find anything that speaks to my specific case. If there is something out there and I missed it, I'm sorry.
I am writing a function that reverses a string. It's for a project that comes with some pretty specific guidelines. I'm not allowed to use any functions such as malloc, printf etc and my function needs to return the string that is passed in as an argument. The function needs to be prototyped as follows:
char *ft_strrev(char *str);
This is my funtction:
char *ft_strrev(char *str)
{
int i;
int j;
char c;
i = 0;
j = ;
c = '0';
while(str[j] != '\0')
j++;
while(i != j)
{
c = str[i];
str[i] = str[j];
str[j] = c;
i++;
j--;
}
}
When I call this in a main and test it with putstr https://github.com/kigiri/userpref/blob/master/ft_42/ft_putstr.c it compiles fine, but at runtime I get a seg fault.
What am I doing wrong?
There are two problems with your code (apart from this j =; stuff.
After the first while look j points to the '\0' after the end of the string rather than to the last character of the string.
Condition of the second look does handle the situation when j - i is odd initially. for example, if i is 0 and j is 1 initially, then, after first iteration, i will be 1 and j will be 0, so condition will still be true.
Here is fixed code:
char *ft_strrev (char *str)
{
int i = 0, j = 0;
while (str [j] != '\0') j++;
while (i < --j) {
char t = str [i];
str [i++] = str [j];
str [j] = t;
}
return str;
}

Cannot find the bug in my code to delete a character from a string

#include <stdio.h>
#include <stdlib.h>
void squeeze(char s[], int c);
int main(){
int i, max = 200,c;
char s[max];
for(i=0; i <max-1 && (c=getchar())!=EOF; ++i){
s[i] =c;
}
squeeze(s, c);
printf("%s", 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';
}
The above stated code is supposed to remove all the occurrences of character c from the input string. The code is compiling without any errors and yet whilst running the code it is printing the same input string even when it contains the character c. I can't figure out where I am going wrong here.
You never terminate s before calling squeeze(), so it's not a valid string. This code thus has undefined behavior.
Then this:
squeeze(s, c);
should probably be
squeeze(s, 'c');
if you want to remove the character 'c'. Now you're passing the variable c, whose value there is EOF; it makes no sense.
main change like as
...
printf("Input string : ");
fgets(s, sizeof s, stdin);
printf("Enter you want to delete characters : ");
c = getchar();
squeeze(s, c);
...
If I understand correctly your were trying to removed all occurrences of the last character read in squeeze, among other things, it was failing because you were passing the null-terminator s[i] as c to squeeze. That would never work. A few revisions and it now removes all occurrences of the last char read:
#include <stdio.h>
void squeeze(char *s, int c);
int main(){
int i = 0, max = 200, c = 0;
char s[max];
while ((c = getchar()) != EOF && c != '\n' && i < max-1)
s[i++] = c;
s[i] = 0;
if (i > 0)
squeeze (s, s[i-1]);
printf("\n %s\n\n", s);
return 0;
}
void squeeze (char *s, int c) {
int i = 0, j = 0;
while (s[i]) {
if(s[i] != c){
s[j++] = s[i];
}
i++;
}
s[j] = 0;
}
Output
$ ./bin/squeeze <<< "this_is_first_z_and_last_z"
this_is_first__and_last_

Can someone interpret the for loop for me?

#include <stdio.h>
#define MAXLINE 10
void reverse(char s[]);
void getline(char b[], int lim);
int main() {
char s[MAXLINE];
getline(s, MAXLINE);
reverse(s);
return 0;
}
void reverse(char s[]) {
int i;
int len = 0;
for (i=0; s[i] != '\0'; i++) {
len = len + 1;
}
char b[len + 1];
for (i = 0; i < len; i++) {
b[(len - 1) - i] = s[i];
b[len] = '\0';
}
printf("%s : %s\n", s, b);
}
void getline(char b[], int lim) {
char c;
int i;
for (i=0; i < lim-1 && (c = getchar())!= EOF && (c!='\n'); ++i) {
b[i] = c;
}
if (c == '\n') {
b[i] = '\n';
}
}
why am i getting an error for the get line unction? It says in Xcode "conflicting types for 'get line'. Also in another error, it says "Too few arguments to function call, expected 3, have 2?
Also can someone explain the order of evaluation for the "condition" part of the for loop? (I'm talking about the &&'s). Thanks a lot!!!
(1)..Your program is correct.But,already one library function getline is exist in library.We know that predefined function's prototype declarations are present in header file.For getline predefined function, declaration is already present in stdio.h...In your program, you are also declared prototype for getline .We know well that It is not possible two declarations for one function.So only you got error.Try to run your program with othername for that function...
(2)..for (i=0; i < lim-1 && (c = getchar())!= EOF && (c!='\n'); ++i)
In for loop you are checking three conditions..you are checking for '\n' also.so,You should give input as string format only.But actually it is not string.You should give characters as input continuously without pressing ENTER.

is this example of k&r chapter 2 wrong?

/* 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;
}

How do I complete K&R Exercise 2-4?

I'm learning how to write programs in C using the k&r book (The C Programming Language) and I have a problem with one of the exercises. It's asking me to detect and remove a character in string s1, which matches any characters in the string s2.
So, say s1 = "A";
And s2 = "AABAACAADAAE"
I want it to return "BCDE"
I know I'm on the right path towards it, i just don't know how to design programs very well, could you give me any additional tips. I tried to read about the binary search tree algorithm, but felt it was a little too advanced for this mundane task.
Thanks everyone!
/* An alternate version of squeeze(s1, s2) that deletes each character in
* s1 that matches any character in the string s2
*
* Angie#odfx.org
*/
#include <stdio.h>
#include <string.h>
void squeeze(char s[], char t[]);
char string[] = "BAD";
char sstring[] = "ABC";
int
main(void)
{
squeeze(string, sstring);
return 0;
}
void
squeeze(char s[], char t[])
{
int i, j, d;
d = 0;
if(strstr(s, t) == NULL)
printf("%c", s[i]);
s[j] = '\0';
}
Great book. If I were you, I would proceed exactly as for the squeeze() in section 2.8, but instead of a direct comparison (s[i] != c) I would write and exploit a function
int contains(char s[], int c)
which returns 1 if the string s contains c, 0 otherwise. Start with the simple approach; when it works you may improve performance with more complex solutions (binary search, but note that the problem doesn't require the characters in s2 to be in a particular order).
A binary search is way overkill for this. You need three indices. One index (i) to walk through s, one index (k) to walk through t, and one index (j) to keep track of where you are in s for the characters that you need to keep because they are not in t. So, for each character in s, check and see if it is in t. If it is not, keep it in s.
void squeeze(char *s, char *t) {
int i, j, k;
int found = 0;
for(i = j = 0; s[i] != '\0'; i++) {
found = 0;
for(k = 0; t[k] != '\0' && (found == 0); k++) {
if(t[k] == s[i]) {
found = 1;
}
}
if(found == 0) {
s[j++] = s[i];
}
}
s[j] = '\0';
}
Here is my very clear and simple answer with some logical explanation.
#include<stdio.h>
void squeeze();
Inside main we type our tested string and wantbedelete string that has the chars that we want to delete from yourstring.
int main()
{
char yourstring[] = "AABAACAADAAE";
char wantbedelete[] = "A";
squeeze(yourstring, wantbedelete);
printf("%s", yourstring);
return 0;
}
The logic inside the squeeze function is as follows,
loop inside the wantbedelete char by char
then, for any char found in wantbedelete we loop through the whole yourstring
then, we compare if the two founded char does not match, we update (save) that char from yourstring to yourstring so basically here just we define a new index(k) to keep track and update the only wanted characters
now the trick here is that we want to reset our index each time we go back again to the outer loop that is looping through each char we intend to delete so that we end up with the only wanted string.
I highly recommend using the debugger and following each line inside the squeeze function so that you would be able to understand the logic more clearly.
void squeeze(char s1[], char s2[])
{
int i, j, k;
k = 0;
for (i = 0 ; s2[i] != '\0' ; i++) /* loop for each char we want to delete with index i */
{
for (j = 0 ; s1[j] != '\0'; j++) /* loop for each char we want to keep with index j */
{
if (s2[i] != s1[j]) /* if the two chars do not match */
{
s1[k++] = s1[j]; /* update s1 with the char that we want to keep using index k */
}
}
s1[k] = '\0'; /* since we update all char that we want to keep, the last char of index k must be empty */
k = 0; /* reset index k so we will be ready for the next char that we want to delete from s1 */
}
}
You don't need a fancy binary search to do the job. What you need is a double for loop that check for occurrence of each char in one string in another, and copy the non-occurring chars into a third char array (which is your result).
Code can be something like the following (not tested!):
char *s1, *s2, *result; /* original strings and the result string */
int len1, len2; /* lengths of the strings */
for (i = 0; i < len1; i++) {
for (j = 0; j < len2; j++) {
if (s1[i] == s2[j]) {
break;
}
}
if (j == len2) { /* s1[i] is not found in s2 */
*result = s1[i];
result++; /* assuming your result array is long enough */
}
}
void squeeze(char s1[], char s2[])
{
int i,j,k;
char c;
for(i=0;s2[i]!='\0';i++)
{
c=s2[i];
for(j=k=0;s1[j]!='\0';j++)
if(s1[j]!=c)
s1[k++]=s1[j];
s1[k]='\0';
}
}
this is my function:
void squeeze(char s1[],char s2[])
{
int i,j,p;
int found;
p=0;
for(i=0;s1[i]!='\0';i++)
{
for(j=0;s2[j]!='\0';j++)
if(s1[i]==s2[j])
found=YES;
else
found=NO;
if(found==NO)
s1[p++]=s1[i];
}
s1[p]='\0';
}

Resources