I'm trying to write a function for printing text in C for PIC microcontrollers (I think it's based on gcc).
void print(char[] text);
void print(char[] text)
{
for(ch = 0; ch < sizeof(text); ch ++)
{
do_something_with_character(text[ch]);
}
}
and call it like this:
print("some text");
I'm getting compiler complaints about wrong brackets.
What is wrong with this?
How can I use char array pointer in this case?
The correct syntax is
void print(char text[])
or
void print(char *text)
In print(), you cannot use sizeof operator to find out the length of string text, you need to use strlen() (include <string.h> first) or test whether text[ch] is \0.
I would do it like this:
void print(char *text);
void print(char *text)
{
while(*text)
{
do_something_with_character(*text);
++text;
}
}
As mentioned in other answers, your syntax is incorrect. The brackets belong after text.
Also of significant importance, sizeof does not do what you're expecting here:
void print(char[] text)
{
for(ch = 0; ch < sizeof(text); ch ++)
^^^^^^
Remember, sizeof is a compile-time operator - the compiler replaces it with the size while the code is being built. It can't possibly know the size at runtime.
In this case, sizeof(text) is always going to return sizeof(void*), or 4 on most 32-bit systems. Your platform may vary.
You have two options:
Pass the length in another parameter to print.
Treat the char[] as a "C string", where the length is unknown, but the string is terminated by NUL character.
The latter is your best bet, and you should probably replace char[] with char*.
Here we use a NUL-terminated string, and iterate over it with a pointer:
void print(const char* text)
{
const char* p;
// Iterate over each character of `text`,
// until we reach the NUL terminator
for (p = text; *p != '\0'; p++) {
// Pass each character to some function
do_something_with_character(*p);
}
}
You have to place the square brackets in the correct place:
void print(char[] text);
void print(char[] text)
void print(char text[]);
void print(char text[])
or use pointer notation:
void print(char *text);
void print(char *text)
Also, note that even if you use the array notation, the parameter is effectively rewritten to a pointer, and then the code in the body of the function:
for(ch = 0; ch < sizeof(text); ch ++)
is wrong. You almost certainly don't want the 4 or 8 bytes that is the size of the pointer. You probably want:
size_t len = strlen(text);
for (size_t ch = 0; ch < len; ch++)
If you can't declare variables in your loop (C99 or later required), declare it separately. You didn't show the declaration of ch in your code. If it compiled, that means ch is a global variable — which is pretty horrid.
Note that the ++ operator binds tightly and should not be separated from its operand by spaces.
Pass C-style string by pointers, or brackets after variable name:
void print(char *text);
^
or
void print(char text[]);
^^
To calculate the length of a string, use strlen not sizeof.
int len = strlen(text);
for(ch = 0; ch < len; ch ++)
^^^^
Judging on your question and the observation that you are probably a beginner in C, I'll attempt to answer your question without using pointers like the other answers here.
First off, Jonathon Reinhart makes an excellent point, that sizeof is not the proper usage here. Also, as others pointed out, the correct syntax for an array of characters, which is what you are using in your code, is as follows:
// empty character array
// cannot be changed or given a value
char text[];
// character array initialized to the length of its content
char text[] = "This is a string";
// character array with length 1000
// the elements may be individually manipulated using indices
char text[1000];
In your case, I would do something like this:
#include <string.h>
void print(char text[]);
int main()
{
char text[] = "This is a string";
print(text);
return 0
}
void print(char text[])
{
// ALWAYS define a type for your variables
int ch, len = strlen(text);
for(ch = 0; ch < len; ch++) {
do_something_with_character(text[ch]);
}
}
The standard library header string.h provides the strlen function which returns an integer value (actually an unsigned long) of the length of the string excluding the terminating NULL character \0. In C, strings are just arrays of characters and the way you specify the end of a string is by including \0 at the end.
Related
#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(;i<100;i++)
{
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(;i<100;i++)
{
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
You are returning a pointer to automatic variables en and de which are stored in the stack. This in turn means after returning from the functions encrypt and decrypt their place in the memory can be used by any other variable.
so to correct that, you need to define en and de as static.
const char *encrypt(char *str){
static char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1){
static char de[100];
int i=0;
for(;i<100;i++){
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
Though a more suitable and safer way to implement that would be:
#include<stdio.h>
void encrypt(char *str, char *encStr);
void decrypt(char *str1, char* decStr);
int main()
{
char str[100], encDecStr[100];
//Encryption
printf("Enter String for encryption\n");
scanf("%s", str);
encrypt(str, encDecStr);
printf("%s after encryption is %s\n",str,encDecStr);
//Decryption
printf("Enter String for decryption\n");
scanf("%s", str);
decrypt(str, encDecStr);
printf("%s after decryption is %s",str,encDecStr);
return 0;
}
void encrypt(char *str, char *encStr)
{
for(char *c = str; *c != '\0'; c++)
{
*encStr++ = *c + 1;
}
*encStr='\0';
}
void decrypt(char *str1, char* decStr)
{
for(char *c = str1; *c != '\0'; c++)
{
*decStr++ = *c - 1;
}
*decStr++='\0';
}
Note: The code was not fully tested for different use cases.
There are quite a number of errors in your code:
Returning arrays with local storage duration:
The array's life time ends (i.e. it ceases to exist) as soon as you exit from the function, thus the pointer returned is dangling, reading from it is undefined behaviour
You write beyond the bounds of your local array: en[i] = '\0' with i being 100 after the loop is out of the range of valid indices from 0 to 99, which again is undefined behaviour.
You have differing offsets for encrypting (1) and decrypting (3).
Simply adding an offset without further checks (or modulo operations) will produce different character sets for input and output strings (might be your least problem...).
You always en-/decode the entire array, which is more than actually needed. Additionally the terminating null character then is encoded as well, resulting in different lengths of input and output and garbage at the end of encoded string.
Use of gets is dangerous as it allows a user to write beyond the input array, resulting in undefined behaviour. This is the reason why it actually has been removed from C language with C11 standard – which introduces a safe alternative gets_s. Yet another alternative (especially for pre-C11 code) is fgets.
For the dangling pointer problem there are several options:
Making the array static (as mentioned already):The disadvantage of this approach is that the function is not thread-safe any more. Additionally calling the function more than once overwrites previous results, if you haven't evaluated already or copied them they are lost.
Returning a dynamically allocated array, see malloc function. This comes with the risk of the caller forgetting to free the allocated memory again, which would result in a memory leak
Changing the input array in place: Disadvantage of is having to copy the input into a backup if it is yet needed afterwards.
Letting the caller provide the buffer.
Last option is most flexible and most idiomatic one, so I'll concentrate on this one:
void caesar(char const* input, char* output, int offset)
{
int const NumChars = 'z' - 'a';
offset = offset % NumChars + NumChars;
// ^ assures valid range, can still be negative
// ^ assures positive value, possibly
// out of range, but will be fixed later
for(;*input; ++input, ++output)
{
int c = *input - 'a';
// distance from character a
c = (c + offset) % NumChars;
// ^ fixes too large offset
*output = 'a' + c;
}
// as now iterating *until* null character found we now *need*
// to add it (in contrast to original version with whole array!)
*output = 0;
}
This variant includes an interesting idea: Let the caller define the offset to be applied! The modulo operation assures the valid range of the character, no matter how large the offset is. The great thing about: If a user encoded with some number n, exactly the same function can be used to decode again with -n (which is why I simply named it caesar according to the algorithm it implements). Note that this is untested code; if you find a bug please fix yourself...
Be aware, though, that this code still has two weaknesses:
It assumes ASCII encoding or compatible – at least one where letters a to z are in contiguous range, a is first character, z is last one. This is not true for all encodings, though, consider the (in-?)famous EBCDIC.
It assumes all input is in range of Latin minuscules only (from a - z), it does not consider white-space, digits, capital letters, punctuation marks... You might want to include special handling for all of these or at least the ones you might use.
You could fix these e.g. (many other variants are thinkable as well) by
converting all characters to either upper or lower case (toupper((unsigned char)*input) – assuming case doesn't matter)
search in an array of valid characters ("ABC...XYZ012...89") for the appropriate index and if found encode like above with NumChars being array length, otherwise (whitespace, punctuation) just leave as is.
In any case, the function would then be called like:
char input[128]; // prefer powers of 2 for array lengths...
char en[sizeof(input)];
char de[sizeof(input)];
gets_s(input, sizeof(input));
caesar(input, en, 7);
// en contains encrypted string, could e.g. be printed now
caesar(en, de, -7);
// de contains decrypted string
// you could even encode/decode in place:
caesar(input, input, 7);
// just be aware that this will fail, though, for the case if input
// and output overlap and input starts before output, as then at
// some point already encoded values will be read as input again:
// caesar(input, input + 1, 7) fails!!!
There's some issues in your code :
Not a very big issue for a beginner , but you should avoid gets function.
Because it doesn't check the input , it can cause buffers overflow and various security problems , try using fgets instead.
In encrypt , and decrypt functions , you are returning the address of an array located in the stack of the function , look :
const char *encrypt(char *str){
char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
Here , Since the en array is declared inside the function , after the return you may get garbage string when trying to read it.
The solution here , is to either malloc it , or declare a static array outside the function , and initialize it.
You are encrypting by adding 1 to the value of the string , and decrypt it by retrieving 3 . I don't know if this is what you intended to do.
Here's a new version of your code , try to check if it suits your need :
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
static char de[100] , en[100] ;
const char *decrypt(char *str1){
memset(de , 0 , 100) ;
int i=0;
for(;i<strlen(str1);i++){
de[i]=str1[i]-1;
}
de[i]='\0';
return (const char*) de;
}
const char* encrypt(char* str){
memset(en , 0 , 100) ;
int i=0;
for(;i<strlen(str);i++){
en[i]=str[i]+1;
}
en[i]='\0';
return (const char*) en;
}
int main(){
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
Your code does not handle a special case for the character 'z'. Thus
en[i]=str[i]+1;
Causes the character '{' to be written to the array en instead. For learning more about why this happens, I recommend you look at ASCII tables and looking at the integer values for alphabets.
Secondly, did you mean to type -3 in there?
de[i]=str1[i]-3;
This won't work if you're planning on using the decrypt() function to decrypt strings that you made using encrypt() because you're adding 1 to the character while encrypting and then subtracting a different number when decrypting, so the result will appear garbled.
I rewrote your code for you, since this is a beginner program, I made as little changes as possible so you can understand it. I WOULD HIGHLY RECOMMEND NOT USING gets() though... See here.
#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
encrypt(str);
printf("%s after encryption is %s\n", str, encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
decrypt(str1);
printf("%s after decryption is %s", str1, decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'z')
{
en[i] = 'a';
continue;
}
en[i] = str[i] + 1;
}
en[i] = '\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'a')
{
en[i] = 'z';
continue;
}
de[i] = str1[i] - 1;
}
de[i] = '\0';
return de;
}
Some criticisms
Like I said, gets() is really bad... See here for more details. Although it might be too complicated for you... A better alternative is fgets!
fgets(str, num, stdin)
takes user input from the console, and then stores it inside the array str, which must be large enough to store at least num characters. Don't worry about stdin if you don't know what that means. But be sure to always write it when using fgets as an alternative to gets
Like others have already posted, albeit using more technical jargon, it's a bad idea to declare an array inside a function and then return that array. You know the function ends when the return statement is hit, and at that point all the variables that were declared inside the function will get destroyed.
That doesn't necessarily mean that you can't read the data that was in them, but it becomes a probabilistic game where there's a teeny-tiny chance that the array will get corrupted after the function exits and before the data in that array is read. This is technically Undefined Behaviour.
I hope you know about pointers. You can modify the array which you passed as a parameter directly and then return that array, thus avoiding accessing an array outside it's lifetime.
Currently, I'm studying c programming language and on the test was a task - Write a function that has two strings as a parameter and need to find and print all unique characters that are present in both strings:
the 'main' function for the test is (and I suspect that all tests are generated using similar function):
int main(void)
{
char *str0 = {"example string", "excelent string"};
solution(2, str0);
return (0);
}
Function should be declared as follow void solution(int size, char **strs);
I don't see any problem to write algorithm. The question is - how to get a second string from **strs?
I tried different approaches just to print second element:
printf("%s", strs[1]);
*strs++;
printf("%s", *strs);
But nothing works.
I guess, that mistake in main function:
Should be something like this: char *str0[] = {"example string", "excelent string"};
Could somebody help - is this mistake in the test and with a provided function to solve this task is impossible or is exist any way to get second string from array?
char *str0 = {"example string", "excelent string"}; is incorrect: it declares a character array, but attempts to define it using array of size 2 containing elements of the type 'character array'. It should be declared as an array of arrays, for example using a fixed size of 2. This works:
#include <stdio.h>
void solution(int size, char **strs)
{
printf("%s\n", strs[0]);
printf("%s\n", strs[1]);
}
int main(void)
{
char *str0[2] = {"example string", "excelent string"};
solution(2, str0);
return 0;
}
I do not consider it a good practice to mix the * and [] pointer notations, but this follows the specifications of the task best, given the definition of the string literal array of size 2.
Continuing from the comment, your brace-initializer {"example string", "excelent string"} is the initializer for an array. (in this case) Specifically in your case, it is the initializer for an array of pointers to String-Literals.
You declare your array and determine the number of elements by:
char *strings[] = { "one", "two" };
size_t nelem = sizeof strings / sizeof *strings;
Once you have your array of pointers, you can pass the array as type char ** because the first level of indirection is converted to a pointer on access. See C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)
Your function declaration can then be:
void solution (size_t size, char **strs);
and you would invoke your function like:
solution (nelem, strings);
A short example would be:
#include <stdio.h>
void solution (size_t size, char **strs)
{
for (size_t i = 0; i < size; i++)
puts (strs[i]);
}
int main (void) {
char *strings[] = { "one", "two" };
size_t nelem = sizeof strings / sizeof *strings;
solution (nelem, strings);
return 0;
}
(note: while nelem and size can be type int, it is more properly size_t -- though the compiler will allow the result of the division to be assigned to int without warning)
Example Use/Output
Which will iterate over the strings outputting each from the function:
$ ./bin/array_ptrs_init
one
two
Determining Unique Characters
Now for the rest of your task outputting unique characters from both strings, you can include string.h and iterate over the characters in one string calling strchr() to determine if the character is present in the second string. If it is, continue; and get the next char to check, or it it is unique (e.g. strchr() returns NULL), output the character as unique. (this part I leave to you)
char* is the array of chars, that is, char * is string.
And equally, for some type of T, T* is considered as the array of T.
So, you assume that char * is a new type such as
typedef char * STRING;
Then you can understand easily.
#include <stdio.h>
typedef const char * STRING;
void solution(int size, STRING * strings)
{
int i = 0;
for (i = 0; i < size; i++)
{
printf("%s\n", strings[i]);
}
}
int main()
{
STRING strings[2] = { "example string", "excelent string" };
solution(2, strings);
return 0;
}
I'm trying to read a string from argv. It should be something like a mathematical function like "-x^2-5" etc.
I've got something like this:
void test(char *function){
int temp = 0;
for (int i = 0; i < strlen(function); i++){
if((function[i] != '+') && (function[i] != ...){
// function[i] is a digit, but still as a char
temp = atoi(function[i]);
}
}
//...
}
int main(int argc, char **argv){
test(argv[1]);
//...
}
This works quite well until the last lap of the loop.
If I use printf("%c", function[i]);, it sais, it's 5.
But atoi(function[i]) gives a segfault. Why?
Right. Let's first take a look at the signature of atoi.
int atoi(const char *str);
Now, what you are passing to it is function[i], and since function is of type char *, function[i] is a char. And your character is most likely not a proper character pointer.
What you'd want to pass to atoi is instead a const char *, which you can get by calling atoi(&function[i]);
As already said by #sham1, atoi expects its parameter to be a C string, this is a null terminated char array, while you have a single char.
But digits are special, because they are required to have consecutive codes. So if you know that a character (say c) is a digit, its value is c - '0'. So you can write:
if((function[i] != '+') && (function[i] != ...){
// function[i] is a digit, but still as a char
temp = function[i] - '0'; // get the int value of a digit character
}
Besides the bug pointed out in other answers, atoi doesn't have any reliable error handling, which is why it is one of the standard library functions that should never be used.
Just forget that you ever heard about atoi and replace it with:
char* endptr;
int result = strtol(str,&endptr,10);
if(endptr == str)
{
// some conversion error
}
strtol is also able to convert an initial part of the string if it contains valid numbers.
I know this code is quite simple; but that message won't stop appearing, can you help me find where the error is?
#include <stdio.h>
void Reverse(char * word[]) {
char temp = word[0];
for (int i = sizeof(word); i >= 0; i--){
for (int j = 0; j<= sizeof(word); j ++){
word[0] = word[i];
}
}
word[sizeof(word)] = temp;
printf("%s", word);
}
void main() {
Reverse(gets(stdin));
return 0;
}
gets returns char*. In this context - It is wrong to write char *[] in the function definition where you are supposedly passing a char array where input characters are being stored using gets. Also char *gets(char *str) - you need to pass a buffer to the gets where the inputted letters will be stored. You didn't pass one.
sizeof doesn't work here. It returns the size of a pointer (char*). You will have to use strlen() to get the length of the string inputted by gets.
More importantly - don't use gets - it's time to use something much safer than gets, namely fgets etc. Buffer overflow is not something you want to deal with.
Suppose you are passing an array of char* to the function reverse. Then the parameter would be char*[] which means nothing other than char** here. Here you will simply pass the char array which you will be using as buffer to gets.
I'm trying to convert a char * to uppercase in c, but the function toupper() doesn't work here.
I'm trying to get the name of the the value of temp, the name being anything before the colon, in this case it's "Test", and then I want to capitalize the name fully.
void func(char * temp) {
// where temp is a char * containing the string "Test:Case1"
char * name;
name = strtok(temp,":");
//convert it to uppercase
name = toupper(name); //error here
}
I'm getting the error that the function toupper() expects an int, but receives a char *. Thing is, I have to use char *s, since that is what the function is taking in, (I can't really use char arrays here, can I?).
Any help would be greatly appreciated.
toupper() converts a single char.
Simply use a loop:
void func(char * temp) {
char * name;
name = strtok(temp,":");
// Convert to upper case
char *s = name;
while (*s) {
*s = toupper((unsigned char) *s);
s++;
}
}
Detail: The standard Library function toupper(int) is defined for all unsigned char and EOF. Since char may be signed, convert to unsigned char.
Some OS's support a function call that does this: upstr() and strupr()
For those of you who want to uppercase a string and store it in a variable (that was what I was looking for when I read these answers).
#include <stdio.h> //<-- You need this to use printf.
#include <string.h> //<-- You need this to use string and strlen() function.
#include <ctype.h> //<-- You need this to use toupper() function.
int main(void)
{
string s = "I want to cast this"; //<-- Or you can ask to the user for a string.
unsigned long int s_len = strlen(s); //<-- getting the length of 's'.
//Defining an array of the same length as 's' to, temporarily, store the case change.
char s_up[s_len];
// Iterate over the source string (i.e. s) and cast the case changing.
for (int a = 0; a < s_len; a++)
{
// Storing the change: Use the temp array while casting to uppercase.
s_up[a] = toupper(s[a]);
}
// Assign the new array to your first variable name if you want to use the same as at the beginning
s = s_up;
printf("%s \n", s_up); //<-- If you want to see the change made.
}
Note: If you want to lowercase a string instead, change toupper(s[a]) to tolower(s[a]).
toupper() works only on a single character. But there is strupr() which is what you want for a pointer to a string.
How about this little function? It assumes ASCII represented chars and modifies string in place.
void to_upper(char* string)
{
const char OFFSET = 'a' - 'A';
while (*string)
{
*string = (*string >= 'a' && *string <= 'z') ? *string -= OFFSET : *string;
string++;
}
}
toupper() works on one element (int argument, value ranging the same as of unsigned char or EOF) at a time.
Prototype:
int toupper(int c);
You need to use a loop to supply one element at a time from your string.