1

I am trying to understand a bit about pointers and how to use them with char types. Here I am declaring a char and assigning it a value. Then I declare a pointer variable. Using the '&', I believe I am getting the address of the variable - I'm trying to dereference the pointer and set it so the *s1 variable will print out the value in x1. I know I can achieve this in other ways, but, I really want to understand how to pass the value from a char to a char pointer. I am getting an incompatible pointer type warning and I don't understand why?

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

/* Global variable: accessible to all threads */
int total = 0;
int n1,n2;
// char *s1,*s2;
FILE *fp;

/* Prototypes */
int num_substring(void); /* Given Substrings Function */
int readf(void); /* stand in for file read */

/* Input for testing - will be from readfile */
char x1[49] = "vgccgcporertfewjjqhjreuvpubfiterhmdxereotxmhcnsre";  
char x2[2] = "re";          
char *s1;   /* A pointer to an char ("*s1" is a char, so s1
                       must be a pointer to an char) */
char *s2;

int main(int argc, char* argv[]) {
    readf();

    return 0;
}   /* MAIN */

// make a function to return s1, s2, n1 ,n2 maybe fp
int readf(void){
    s1 = &x1;           /* Read it, "assign the address of x1 to s1*/
    s2 = &x2;  
    /* Input for testing - will be from readfile */
    n1=strlen(s1);                 /*length of s1*/
    n2=strlen(s2)-1;               /*length of s2*/
    /* ----------------------------------------- */
    return -1;
}   /* readf */
ndim
  • 35,870
  • 12
  • 47
  • 57
Joseph
  • 301
  • 3
  • 13
  • 1
    You probably get a compiler warning (if not error) about `s1 = &x1;` because `&x1` has the type `char (*)[49]` — pointer to array of 49 `char` — which is quite different from `char *`. Ditto the next line. You should be showing the exact compiler errors for the code shown, which should be an MNCVE ([MCVE]). You should identify the lines where the errors/warnings are reported. You have too many global variables for the code to be good. You declare but don't call or define `num_substring()` — which misleads people about the size of your code (it is fairly small after all). – Jonathan Leffler Jun 25 '17 at 05:42
  • 1
    BTW, `strlen(s1)` and `strlen(s2)` invoke UB as the "strings" `s1` and `s2` point to aren't NUL-terminated. Increase the size of `x1` and `x2` to 50 and 3 respectively to avoid this UB. – Spikatrix Jun 25 '17 at 05:58
  • 1
    As a matter of practice, you want to avoid the use of global variables unless absolutely necessary (none of which apply here). You should declare all your variables within `main` and pass them as parameters as needed. See [**Accessing global variables in pthreads in different c-files**](https://stackoverflow.com/questions/7382636/accessing-global-variables-in-pthreads-in-different-c-files) – David C. Rankin Jun 25 '17 at 07:19

1 Answers1

3
s1 = &x1;

is not correct. From

char x1[49] = "vgccgcporertfewjjqhjreuvpubfiterhmdxereotxmhcnsre"; 

x1 is an array of characters. So &x1[0] is the address of the first character.

 s1 = &x1[0]; // should get rid of that warning

Interestingly, you can interchange &x1[0] with x1 by convention (ie both means the same thing). So the below should also be true :

 s1 = x1; // should get rid of that warning

But if you can write s1 = x1;, then you can't write s1 = &x1; for the obvious reason which is known to you.

Edit2

It is not safe to write

char x1[49] = "vgccgcporertfewjjqhjreuvpubfiterhmdxereotxmhcnsre";

"..." is a null terminated sequence of characters(sometimes conveniently called a string) which means a null character '\0' will be appended to what you put inside the double quotes. If you put the exact number of characters , as mentioned in the array index, or more inside the double quotes, then when the compiler append the '\0', then you access outside the boundary of the array. Luckily, C has a flexible mechanism whereby you can omit the array index and the compiler does the job of allocating a memory block large enough to hold your string. So change it to

char x1[] = "vgccgcporertfewjjqhjreuvpubfiterhmdxereotxmhcnsre";

Note Thanks @david-bowling for the [ hint ].

sjsam
  • 21,411
  • 5
  • 55
  • 102
  • 2
    It should be `char x1[50] = "vgc...";` to include space for the null terminator, or better yet, `char x1[] = "vgc...";`, allowing the compiler to find the correct size. – ad absurdum Jun 25 '17 at 05:51
  • @DavidBowling : Aww! I didn't notice that. Thank you, will put a note.. – sjsam Jun 25 '17 at 05:52
  • this worked wonderfully. So &x1 is the memory address, by using &x1[0] we are looking at the address of the first character of the string. Does the *s1 pointer then take on the full string of x1? You don't have to iterate through every character? – Joseph Jun 25 '17 at 05:52
  • I didn't know you could declare the array `x1[]` , that's fantastic – Joseph Jun 25 '17 at 05:54
  • @Joseph: C strings have no magic. They are just byte arrays with a zero on the end. So " *s1 pointer then take on the full string of x1?" makes no sense. `s1 = x1` or `s1 = &x1[0]` do the same thing: point to the first array element. Then, as they always do, the string functions like `strlen` iterate through every character. – Zan Lynx Jun 25 '17 at 06:45
  • Ok, final question, in a loop of `j = 1 to strlen(s1)+1`, the element `s1[j]` returns an integer. I don't follow why it's an integer as opposed to the character element of the string? – Joseph Jun 25 '17 at 07:11
  • @Joseph, it looks like you are confused (depends on what you are iterating), but you cannot iterate `1` to `strlen(s1) + 1`. Why? The valid indexes for `s1` are `0` to `strlen(s1) - 1`. Any index larger than `strlen(s1) - 1` is *Undefined Behavior*. If you want to iterate using `j`, its `for (j = 0; j < strlen (s1) - 1; j++) { ... do something with s1[j] ...}` and since `s1` is a *string*, you can simply do `for (j = 0; s1[j]; j++) {...}` – David C. Rankin Jun 25 '17 at 07:48
  • @DavidC.Rankin I don't know why I posted that question that way, I know I have to set the loop up that way - but thank you! My real question is that `s1[j]` returns an integer even though `s1` is a string - I would intuit that it would return the individual elements of the string? (letters) – Joseph Jun 26 '17 at 03:42
  • @Joseph Yes, whether `s1` is an **array** or a pointer to a string in any block of memory, you can *dereference* the array or pointer using *array index notation* (e.g. `foo[x]` -- which is equivalent to `*(foo + x)`). So if `char s1[] = "abc";`, then `s1[2]` is `'c'` and `s1[3]` points to the *nul-terminating* character (which has a *decimal* value of `0` and the *character* equivalent `'\0'`) Which means you can *nul-terminate* a string with either `foo[length] = 0` or `foo[length] = '\0';` (same thing). Meaning with `s1[j]` above, when `j = length`, and `s1[j] = 0`, the loop terminates – David C. Rankin Jun 26 '17 at 05:21