passing array of characters to function in c - c

void skip(char *msg)
{
puts(msg+6);
}
char *message="Don't call me";
skip(message);
My doubt is why we don't use
puts(*(msg+6)) to display text from 7th character onward;
according to me (msg+6) refers to memory and *(msg+6) content

*msg is essentially a reference to a single char, not to the string of char's. due to this char * and char[] are essentially the same thing and you don't need to dereference character pointer in C because compiler automatically print fully string from given base address upto '\0' not get. you can also refer this for more info .

#include <stdio.h>
void skip(char *msg) {
puts(msg + 6);
}
int main() {
char *message = "Don't call me";
skip(message);
}

This is what you can find in puts manual:
int puts(const char *s);
as you can see it also expects pointer to a content as a parameter, rather than an actual value.

Related

Why must I pass a string by reference in order to change where it points?

I'm acquainting myself with c-strings and pointers by using a very simple program.
This version, which passes in a string by reference, works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(char **string) {
*string = (char *)malloc(5);
char *temp = "hell";
strcpy(*string, temp);
}
int main(int argc, char *argv[]) {
char *string = NULL;
test(&string);
printf("%s\n", string);
return 0;
}
It prints "hell".
This version, which simply passes the string by value, does not work, and results in a SEGFAULT:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void test(char *string) {
string = (char *)malloc(5);
char *temp = "hell";
strcpy(string, temp);
}
int main(int argc, char *argv[]) {
char *string = NULL;
test(string);
printf("%s\n", string);
return 0;
}
From what I know, the first version makes sense because I pass in the address of the address of the string. Thus, when I dereference this double pointer, I get the real address of the string and can reassign it with malloc.
The second version, however, I'm kind of unclear why it doesn't work. In this version I pass the address of string into the test function. I read that everything in C is passed by value but that array names are actually addresses. Doesn't this mean that I'm passing in the actual address of string into test? Shouldn't things work out the same? I'm confused, please help me out.
Remember This : In C programming to use a value,you pass "by value". To change a value you must pass "by address". So,if what you want to change is an address,then you need to pass its address to change it.otherwise you may only use it.
When you pass an argument "by value", the value of the argument is copied into the formal argument in the function. Changing a copy (in your case string inside the test function) will of course not change the original (string in the main function).
On a side-note, C doesn't actually have "pass by reference", it only have pass by value. You emulate pass by reference by using pointers.
In your second version, string itself is being passed by value, so you simply cannot change string itself. This is for the similar reason you cannot change the value of an int or float when it is passed by value. While an argument is being passed by value, there is a local copy created in the called function's stack.
You can always change the content of string, however.
In C, array type is represented as a pointer to its first element. * in type means "pointer to", but outside of type means "dereference pointer". When you pass argument to function, in the body of function, you have copy of the thing, that you passed. Lets analyse your code with that in mind:
void test(char **string) { //expect pointer to string
*string = (char *)malloc(5); //dereference pointer to string and allocate memory (*string is of type char*, it is a string)
char *temp = "hell"; //create new string
strcpy(*string, temp); //copy new string to the old one
}
int main(int argc, char *argv[]) {
char *string = NULL; //create empty pointer (string is array, which is pointer to char), but NULL is not a valid string
test(&string); //pass pointer to string
printf("%s\n", string); //print string
return 0;
}
**sting did not change, but its contents *string did.
And in the second one:
void test(char *string) { //with this type, you could modify, what is actual string content (for example first letter), but you pass here NULL, so there is nothing you can do
string = (char *)malloc(5); //here, you are changing only COPY of the pointer, that you passed in main
char *temp = "hell"; //create another string
strcpy(string, temp); //copy new string to the one created, after this operation pointer to the string is lost
}
int main(int argc, char *argv[]) {
char *string = NULL; //the same
test(string); //pass the string, you are screwed here, values in C are passed by copying, so even if you modify the string correctly, you will not see the result
printf("%s\n", string); //the string variable never changed from NULL, so you get the error
return 0;
}

Error in initializing array in C

Below is my code:
#include <stdio.h>
#include <stdlib.h>
typedef int index_key;
typedef char text_t;
text_t *create_text()
{
//text_t text[SIZ];
text_t *c;
text_t text[]="fl";
c= text;
return c;
}
int main()
{
text_t * create();
return 0;
}
I get an error - expected expression before ‘]’ token. Why is this error occuring? Isn't text[] a global declaration and I can access it anywhere? What is wrong in this program and how should I correct it.
You cannot have an array definition like
text_t text[];
Either specify the size,
#define SIZ 256 //arbitary value
text_t text[SIZ];
or use initializer.
text_t text[] = {`A`, `B`, `C`};
EDIT:
As per the latest addition, please be informed that "sldk" (as you've iused) and {'s', 'd', 'l', 'k'} (as i've suggested) are not the same. The former is a string literal while the later being initalizer list of chars. You can use the second in your case, not the first one.
EDIT 2
That said, your create_text() function is wrong. Effectively, you're returning the address of a local variable text. Incorrect. Will invoke UB.
I see the following problems:
text_t text[];
is a declaration, not a definition. You have to add a line that defines text, such as:
text_t text[100];
The line
text[]="sldk";
is wrong on two accounts.
You cannot assign to an array using the = operator.
You cannot use text[] to access the array.
Here's a fixed version of your program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int index_key;
typedef char text_t;
// This is a forward declaration of the array.
text_t text[];
text_t *create()
{
text_t *c;
// One way to get some string into a char array.
strcpy(text,"sldk");
c = text;
return c;
}
// This is the definition of the array.
text_t text[100];
int main()
{
text_t * create();
return 0;
}
Update
Regarding your updated create_text function...
It should work since string literals are stored in read-only memory of the program. It will lead to problems as soon as you try to change anything in it. It's better to use a safer approach, such as:
text_t *create_text()
{
text_t *c = malloc(20);
strcpy(c, "fl");
return c;
}
The C language does not have a built in string data type unlike C++, Java or C#.
The strings are represented as arrays of characters in C. So any array in C should have some size.
int numbers[10];
char string[50];
The C function which operate on these types of strings ( like strlen which calculates the length of the strings expects a 'null' or '\0' character at the end of the array.
Initializing a character array with string literal like "test" will automatically insert a null character at the end.
char str[10] = "test";
characters stored {'t','e','s','t','\0'}
If you are initializing it with comma separated characters, you need to explicitly specify this character.
char str[10] = {'t','e','s','t', '\0'}; //explicit null character
So, generally the array size is one more than the maximum size of the string you want to store. So it is quite common to see declaration like the following.
char name[MAXLEN+1];
If you are using C++, you can use a build-in data type called string.
string str;
Hope this helps

C programming strcat using pointer

I am a beginner in C. I wanted to make strcat function using pointers. I made it but don't know what is wrong with it. I used gcc compiler and it gave segmentation fault output.
#include<stdio.h>
#include<string.h>
char scat(char *,char *);
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
while(*q!='\0') printf("the concatenated string is %c",*q);
}
char *scat(char *s,char *t)
{
char *p=s;
while(*p!='\0'){
p++;
}
while(*t!='\0'){
*p=*t;
p++;
t++;
}
return p-s-t;
}
This one works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *scat(char *,char *); /* 1: your prototype was wrong */
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
printf("cat: %s\n", q); /* 2: you can use %s to print a string */
free(q);
}
char *scat(char *s,char *t)
{
char *p=malloc(strlen(s)+strlen(t)+1); /* 3: you will have to reserve memory to hold the copy. */
int ptr =0, temp = 0; /* 4 initialise some helpers */
while(s[temp]!='\0'){ /* 5. use the temp to "walk" over string 1 */
p[ptr++] = s[temp++];
}
temp=0;
while(t[temp]!='\0'){ /* and string two */
p[ptr++]=t[temp++];
}
return p;
}
You have to allocate new space to copy at the end of s. Otherwise, your while loo[ will go in memory you don't have access to.
You shoul learn about malloc() here.
It is undefined behaviour to modify a string literal and s, and eventually p, is pointing to a string literal:
char* s = "james";
s is passed as first argument to scat() to which the local char* p is assigned and then:
*p=*t;
which on first invocation is attempting to overwite the null character an the end of the string literal "james".
A possible solution would be to use malloc() to allocate a buffer large enough to contain the concatentation of the two input strings:
char* result = malloc(strlen(s) + strlen(p) + 1); /* + 1 for null terminator. */
and copy them into it. The caller must remember to free() the returned char*.
You may find the list of frequently asked pointer questions useful.
Because p goes till the end of the string and then it starts advancing to illegal memory.
That is why you get segmentation fault.
It's because s points to "james\0", string literal & you cannot modify constant.
Change char *s="james"; to char s[50]="james";.
You need to understand the basics of pointers.
a char * is not a string or array of characters, it's the address of the beginning of the data.
you can't do a char * - char* !!
This is a good tutorial to start with
you will have to use malloc
You get a segmentation fault because you move the pointer to the end of s and then just start writing the data of p to the memory directly following s. What makes you believe there is writable memory available after s? Any attempt to write data to non-writable memory results in a segmentation fault and it looks like the memory following s is not writable (which is to expect, since "string constants" are usually stored in read-only memory).
Several things look out of order.
First keep in mind that when you want to return a pointer to something created within a function it needs to have been malloc'ed somewhere. Much easier if you pass the destination as an argument to the function. If you follow the former approach, don't forget to free() it when you're done with it.
Also, the function scat has to return a pointer in the declaration i.e. char *scat, not char scat.
Finally you don't need that loop to print the string, printf("%s", string); will take care of printing the string for you (provided it's terminated).
At first, your code will be in infinte loop because of the below line. you were supposed to use curely braces by including "p++; t++ " statements.
while(*t!='\0')
*p=*t;
though you do like this, you are trying to alter the content of the string literal. which will result in undefined behavior like segmentation fault.
A sequence of characters enclosed with in double quotes are called as string literal. it is also called as "string". String is fixed in size. once you created, you can't extend its size and alter the contents. Doing so will lead to undefined behavior.
To solve this problem , you need to allocate a new character array whose size is sum of the length of two strings passed. then append the two strings into the new array. finally return the address of the new array.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* scat(char *,char *);
void append(char *t , char *s);
int main(void)
{
char *s="james";
char *t="bond";
char *n = scat(s,t);
printf("the concatenated string is %s",n);
return 0;
}
char* scat(char *s,char *t)
{
int len = strlen(s) + strlen(t);
char *tmp = (char *)malloc(sizeof(char)* len);
append(tmp,s);
append(tmp,t);
return tmp;
}
void append(char *t , char *s)
{
//move pointer t to end of the string it points.
while(*t != '\0'){
t++;
}
while( *s != '\0' ){
*t = *s;
t++;
s++;
}
}

what does, "passing argument 2 of 'strstr' makes pointer from integer without a cast," mean in C

I'm trying to have a list of cheeses that you can search through to get to a certain one. When I am done I also want to add info about each one. But every time I run my code I get the error shown in the title. Here is my code:
#include<stdio.h>
#include<string.h>
int main()
{
char cheeses[][20] = {
"Cheddar",
"White Cheddar",
"Colby Jack",
"Gouda",
"Blue Cheese",
"Gorgonzola",
"Asiago",
"Limburger",
"Feta",
"Brie",
};
void find_cheese(char search_for)
{
int i;
for (i = 0; i < 5; i++) {
if (strstr(cheeses[i], search_for))
printf("Cheese %i: '%s'\n", i, cheeses[i]);
}
}
int main()
{
char search_for[20];
printf("Search for: ");
fgets(search_for, 20, stdin);
find_cheese(search_for);
return 0;
}
}
Why is this happening? I've looked it up in my book, but can't seem to find the answer.
The second argument to strstr should be const char*. You're passing a single char.
strstr expects a pointer to char as the second argument:
const char * strstr ( const char * str1, const char * str2 );
while you are passing a char.
void find_cheese(char search_for)
should be
void find_cheese(char *search_for)
because it is looking for a string (char *), not a single character.
strstr() takes a string (char *) as the second argument.
For usage see here.
The problem in your code is you're accepting the passed the array incorrectly:
void find_cheese(char search_for) //This line is wrong
{
What you wanted to do was:
void find_cheese(char search_for[])
EDIT:
Here's what is happening. When you access the array in your main function:
find_cheese(search_for);
What you're actually doing here is passing an address. (When you just access the array search_for you get an address). So when your prototype said it was taking a char the compiler saw the address (4 bytes, looking like an int) and truncated it to fit in a one byte char.
The way you prevent that is by passing the whole "string" (a string in C is a character array). So you can do this by passing search_for as an array, or as a pointer (address to a character array).
void find_cheese(char search_for[])
and
void find_cheese(char *search_for)
Will both work and are equivalent for your needs (passing to strstr())

Question about weird pointer

I study C. Digging in some C source code where I found that line. I have read about pointers, but I did not see such an example.
char *uppercase (char *s);
What that mean ?
It's a declaration of a function that takes a char pointer and returns a char pointer.
That means that the function takes a pointer to a character and returns a pointer to a character i.e the start of the string.
char *uppercase (char *s);
is the same as
char* uppercase (char *s);
Its return type is char*; it returns a pointer.
uppercase is afunction which returns a char type address ( that is, it can be stored in a char pointer ) as its written as char *uppercase...
uppercase() takes a char pointer as argument char *s...
therefore its written as char *uppercase( char *s).
In C the location of the * doesn't matter as long as it is somewhere between the type and name. So char* s is the same as char *s and even char * s.
The same applies to functions and their return types, char* uppercase() is equivalent to char *uppercase() and char * uppercase().
White-space is more or less ignored in C so when writing your own code I recommend you pick one format and stick with it.
The location of the asterisk * can be anywhere: between return type or function name.
It is more logical to keep it on the return type's end i.e. char*

Resources