0

I'm pretty sure it has to do with my use of calloc() but I don't understand why. The objective of the program is for char* C to contain characters of char* A that are not in char* B.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>

char* diff(char* A, char*B);

int main() {
  char* A = {'q','g','e','\0'};
  char* B = {'a','d','e','\0'};
  char* C = diff(A,B);
  printf("%s", C);
  free(C);
  return(0);
}

int search(char* S, char c) {
    int i=0;

    while( S[i]!='\0' ){
        if( S[i]==c ) break;
        i++;
    }
    if( S[i]=='\0' ) return -1;
    else return i;
}

char* diff(char* A, char* B) {
    int i;
    char* C = calloc(strlen(A), sizeof(char));
    assert(C != NULL);
    int lengthC = 0;

    for (i = 0; i < strlen(A); i++) {
        if (-1 != -1) {
            C[lengthC] = A[i];
            lengthC++;
        }
    }

    C[lengthC] = '\0';
    return C;
}
ajwong
  • 11
  • 3
  • 2
    Will `if (-1 != -1)` ever be true? – Jonny Henly Feb 28 '19 at 09:11
  • 4
    `char* A = {'q','g','e','\0'};` doesn't work, you need `char A[] = { 'q','g','e','\0' };` instead, and the same goes for `B` of course. I haven't looked at much else in the program but obviously `if (-1 != -1)` seems sketchy. Oh and you can just do `return 0;`. Not that `return(0);` breaks anything, but it makes it look like a function call whereas it isn't. – Blaze Feb 28 '19 at 09:13
  • 1
    Voting to close as simple typo, since `if (-1 != -1)` is never true and therefore every string gets null terminated at index 0. Enable compiler warnings. In addition, you don't allocate room for the null terminator in the new string. – Lundin Feb 28 '19 at 09:16
  • @Lundin That is clearly *a* typo, but it is not the cause of the specific issue being asked about. In fact, I say this is a good question and have upvoted it because, for once, it includes an MVP that exhibits the described behaviour on my system. – JeremyP Feb 28 '19 at 09:39
  • 1
    @JeremyP Questions where the OP ignores 16 compiler messages and instead goes to ask the internet aren't good in my book, but whatever... – Lundin Feb 28 '19 at 09:55
  • 2
    Also not allocating enough memory - you need `strlen(A)+1` so you'll have space for the `'\0'` – Chris Turner Feb 28 '19 at 10:06
  • Sorry, `if (-1 != -1)` was a typo. – ajwong Feb 28 '19 at 17:14
  • the posted code causes the compiler to output LOTS of warning messages. When compiling, always enable the warnings, then fix those warnings. ( for `gcc`, at a minimum use: `-Wall -Wextra -Wconversion -pedantic -std=gnu11` ) Note: other compilers used different options to produce the same output.\\ – user3629249 Mar 02 '19 at 00:13
  • the function: `diff()` is passed a pointer to the array 'a[]' and the array 'b[]' and is expected to extract where the arrays are different, However, it totally ignores 'b[]' and just copies 'a[]' to 'c[]' So the function does not do what it is expected to do. – user3629249 Mar 02 '19 at 00:19
  • regarding the 'typo' Strongly suggest performing a copy/paste on your actual code so 'typo's never happen – user3629249 Mar 02 '19 at 00:20

2 Answers2

3

Initialization of a char* pointer may look like this:

char *A = { (char*)(void*)(uintptr_t)5 };

This will assign the literal value 5 as the value of the A pointer. The A pointer will point (probably) to an invalid memory location.

The conversion (char*)(void*)(uintptr_t) (or somewhat similar conversion) may be done implicitly by the compiler. It's nice of the compiler to issue at least a warning about implicit conversion from an integer to a pointer.

Also you can "excess" the number of elements inside the { } brackets. Ie.:

char* A = { 1, 2, 3, 4, 5, };

The numbers 2, 3, 4, 5, are ignored, because char* may be initialized from one value only.

The compiler should warn you about those, ex. in gcc i get:

<source>:6:16: warning: incompatible integer to pointer conversion initializing 'char *' with an expression of type 'int' [-Wint-conversion]
    char* A = {'q','g','e','\0'};
               ^~~
<source>:6:20: warning: excess elements in scalar initializer
    char* A = {'q','g','e','\0'};

So:

char* A = {'q','g','e','\0'};

is equal to:

char *A = 113;

As q is equal to 113 according to the ascii table.

113 is an invalid pointer. Later in your code you do:

strlen(A)

which tries to access the memory behind the A pointer. As the pointer is invalid, it is undefined what happens. On your system, you get segmentation fault.

The A variable should probably be changed into an array:

char A[] = {'q','g','e','\0'};

or maybe equivalent:

char A[] = "qge";

Which will create an array of characters and initialize them with proper values.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • 1
    `char* A = { 1, 2, 3, 4, 5, };` is not valid C so it will not compile. There's the wrong amount of initializers, using several is a gnu poop extension not standard C. And there's also a constraint violation since you can't initialize a `char*` with `1`. The problem is simply that the OP doesn't read the compiler log. – Lundin Feb 28 '19 at 09:40
  • `char* A = "ab";` also works. In fact, it came as a surprise to me that `char *A = {'q','g','e','\0'};` does not work, since when I learned C (in the pre-Ansi days) `"ab"` was presented as syntactic sugar for `{ 'a', 'b', '\0'}`. – JeremyP Feb 28 '19 at 09:43
  • @JeremyP No, those are two completely different cases. This is not array initialization but scalar (single item) initialization, since we have a pointer not an array. `char A[] = { ... }` will work just fine. – Lundin Feb 28 '19 at 09:44
  • 1
    @Lundin on my compiler (Apple clang-1000.11.45.5) `char* A = { 1, 2, 3, 4, 5, };` does compile but it emits warnings for the incompatible type and the excess elements in the initialiser. – JeremyP Feb 28 '19 at 09:46
  • @Lundin "those are two completely different cases". I know they are *now*. That was the point of my comment. – JeremyP Feb 28 '19 at 09:48
  • @JeremyP A compiler isn't required to generate errors for standard violations, just "diagnostic messages", such as warnings. If you want to block non-standard C from compiling, use `-pedantic-errors`. – Lundin Feb 28 '19 at 09:51
  • Thank you! This fixed my problem. I was under the impression that I could create an array that way because a pointer of an array is just a pointer to the first element of the array. – ajwong Mar 01 '19 at 23:01
-1

You cannot initialize a pointer this way. char* A = {'q','g','e','\0'}; It may seem to compile on some compilers, it is wrong to initialize this way. Please remember that pointer variables are like integral data type. It actually holds an integral value containing the address of a memory location.

Instead it should be delcared as array: char A = {'q','g','e','\0'}; Array name itself behaves as a pointer in C.(with some limitations of course), So you pass the array name itself as argument to your functions.

Secondly considering your objective of the program: char* C to contain characters of char* A that are not in char* B,

the statement if(-1 != -1) seems like a typo error, i guess you meant

if (search(B,A[i]) == -1)

Also a typecast may be required at the calloc call as it returns void*

char* C = (char *) calloc(strlen(A), sizeof(char));

Considering all these things, below program will acheive your objective:

Hope this helps :)

int main() {
    char A[] = { 'q','g','e','\0' };
    char B[] = { 'a','d','e','\0' };
    char* C = diff(A, B);
    printf("%s", C);
    free(C);
    return(0);
    }

int search(char* S, char c) {
    int i = 0;

    while (S[i] != '\0') {
        if (S[i] == c) break;
        i++;
        }
    if (S[i] == '\0') return -1;
    else return i;
}

char* diff(char* A, char* B) {
    int i;
    char* C = (char *) calloc(strlen(A), sizeof(char));
    assert(C != NULL);

    int lengthC = 0;

    for (i = 0; i < strlen(A); i++) {
        if (search(B,A[i]) == -1) {
            C[lengthC] = A[i];
            lengthC++;
        }
    }

    C[lengthC] = '\0';
    return C;
}
Gautham
  • 16
  • 1
  • 1
    It's pointless to cast the result of calloc. And you didn't catch the missing space for null terminator bug. It should be `char* C = malloc(strlen(A)+1);` instead. – Lundin Feb 28 '19 at 12:27