I got a problem. I want to use one CopyString() function to copy const char*s and char*s to a buffer. It shouldn't be a problem but for some reason my compiler doesn't do the thing I expect it to do (I use MikroC for PIC pro).
void CopyString(char * dest, const char * src, uint8 maxLength){
uint8 i;
for(i=0 ; src[i] && ( i < maxLength ) ; i++){
dest[i] = src[i];
};
}
char test[3]={'2', '0', ' '};
CopyString(buf, test, 3);//gives an error (illigal pointer conversion)
CopyString(buf, (const char *)test, 3); //Doesn't pass the pointer to the array... No idea why not... Do you?
void CopyString2(char * dest, char * src, uint8 maxLength){
uint8 i;
for(i=0 ; src[i] && ( i < maxLength ) ; i++){
dest[i] = src[i];
};
}
const char test[3]={'2', '0', ' '};
CopyString2(buf, "20 ", 3);//All ok
CopyString2(buf, test, 3); //gives an error (illigal pointer conversion)
Anyone knows how to do this? Currently I use CopyString2() and CopyString() in one C document which isn't looking nice and it shouldn't be required. Why would pass a char* to a const char* give problems? The only thing const char* does is making sure the data in the char array won't change within the function, right?
Edit:
Here an edit with the 'whole' example code (which should be a Minimal, Complete, and Verifiable example).
With Keil compiler (which I use to program for ARM mcu's) it compiles just fine (like I would expect) but with MikroC PIC compiler (as far as I can find this is how the compiler is called.) it gives the following error:
18 384 Illegal pointer conversion main.c
(line 18, message no. 384)
23 384 Illegal pointer conversion main.c
(line 23, message no. 384)
void CopyString(char * dest, const char * src, unsigned char maxLength){
unsigned char i;
for(i=0 ; src[i] && ( i < maxLength ) ; i++){
dest[i] = src[i];
};
}
void CopyString2(char * dest, char * src, unsigned char maxLength){
unsigned char i;
for(i=0 ; src[i] && ( i < maxLength ) ; i++){
dest[i] = src[i];
};
}
void main(){
char buf[16]={0,};
char test1[3]={'2', '0', ' '};
const char test2[3]={'2', '0', ' '};
CopyString(buf, test1, 3);//gives an error (illigal pointer conversion);
CopyString(buf, (const char *)test1, 3); //Doesn't pass the pointer to the array
CopyString2(buf, "20 ", 3);//All ok
CopyString2(buf, test2, 3); //gives an error (illigal pointer conversion);
}
It's a problem related to how const variables are implemented for PIC controller. In PIC controllers the RAM and Code are located in different types of memory. RAM is SD-RAM, and code is flash memory.(RAM is accessible through register and ram operations, and code is only automatically decoded, or read through a complicated sequence of assembly operations.) Since the RAM is very small, const values are stored as Return Literal instructions in the Code Memory(To bypass the difficulty of reading Flash memory otherwise), which is larger.
So you can't really do the same operations on both types. It's something you need to learn to live with. I suggest you look at the disassembly of this code to see what's really going on.
I've seen this before in other compilers a long time ago - note I've never used this compiler before.
The "array is-a pointer" concept of C causes a lot of problems with newbies. To prevent that, some compiler writers got very pernickety (it's a word! Look it up!) and required you to pass the address of a character to a const char * instead of merely an array.
Can you try CopyString2(buf, &test[0], 3);?
Or even CopyString2(buf, (const char *)&test[0], 3);?
Related
I can't seem to figure out what is wrong with my code below:
I have a double pointer char array, declared and initialized with the following:
unsigned char **buffer = (unsigned char**) malloc (num * sizeof(char*));
for ( i = 0; i < num; i++ )
{
buffer[i] = (unsigned char*) calloc(PACKETSIZE, sizeof(char));
}
Then I'm trying to copy a string to the middle section of one of the char* arrays, but it does not seem to work. I'm not sure whether my error was with the memory allocation or when I tried to copy. I know for a fact the source char* has content.
The code I'm trying to copy (Header is a struct, I want to write to the array after the memory address of Header for buffer[i], so I'm doing a bit of a pointer arithmetic).
strncpy ((unsigned char *)(buffer[i]+sizeof(Header)), buffer2, bytes_to_copy);
After the code runs, the buffer[i] stays empty.
Here is a sample of the Header struct:
typedef struct Head
{
unsigned int x;
unsigned int y;
} Header ;
Your allocation line:
buffer[i] = (unsigned char*) calloc(PACKETSIZE, sizeof(char));
will set all elements of buffer[i] to zero.
Then, your copy line:
strncpy ((unsigned char *)(buffer[i]+sizeof(Header)), buffer2, bytes_to_copy);
will only set the buffer[i] data that come after the first sizeof(Header) elements.
So, those first sizeof(Header) elements will be zero. Thus, any attempt to use a strxxx function to display that buffer will assume the string is empty (first byte is zero).
I wanna Make strncpy function by code, not by using Library or Header
but There is zsh bus error..... What's wrong with my code? What's the zsh bus error??
#include <stdio.h>
#include <string.h>
char *ft_strncpy(char *dest, char *src, unsigned int n)
{
unsigned int i;
i = 0;
while (i < n && src[i])
{
dest[i] = src[i];
i++;
}
while (i < n)
{
dest[i] = '\0';
i++;
}
return (dest);
}
int main()
{
char *A = "This is a destination sentence";
char *B = "abcd";
unsigned int n = 3;
printf("%s", ft_strncpy(A, B, n));
}
Your implementation of strncpy is fine, the uncanny semantics of the error prone function are correctly implemented (except for the type of n, which should be size_t).
Your test function is incorrect: you pass the address of a string constant as the destination array, causing undefined behavior when ft_strncpy() attempts to write to it. String constant must not be written to. The compiler may place them in read-only memory if available. On your system, writing to read-only memory causes a bus error, as reported by the shell.
Here is a modified version with a local array as destination:
int main()
{
char A[] = "This is a destination sentence";
const char *B = "abcd";
unsigned int n = 3;
printf("%s\n", ft_strncpy(A, B, n));
return 0;
}
Your code exposes one of the very subtle differences in C between an array and a pointer. The line:
char *A = "This is a destination sentence";
declares A as a pointer to a character (string) and then initialises that pointer to the address of a string literal. This string literal is a constant value, and the compiler is allowed to place this in an area of memory that is read-only. Then, when you pass that memory to the ft_strncpy function (via its address), you are attempting to modify that read-only memory.
If you, instead, use the following:
char A[] = "This is a destination sentence";
then you are declaring A as an array of characters and initializing that array with the data from the string literal. Thus, the compiler is now aware that the array is modifiable (you haven't included a const qualifier) and will place that array in memory that can be read from and written to.
I've recently encountered a problem with a script I wrote.
#include "md5.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char* hashfunc (char* word1, char* word2){
MD5_CTX md5;
MD5_Init(&md5);
char * word = (char *) malloc(strlen(word1)+ strlen(word2) );
strcpy(word,word1);
strcat(word,word2);
MD5_Update(&md5,word,strlen(word));
unsigned char* digest = malloc(sizeof(char)* 16); //MD5 generates 128bit hashes, each char has 4 bit, 128/4 = 32
MD5_Final(digest,&md5);
return digest;
}
int main(int argc, char* argv[]){
char* a = argv[1];
char* b = argv[2];
unsigned char* ret = hashfunc(a,b);
printf("%s\n",ret);
printf("%i\n",sizeof(ret));
}
As the hash function returns an array of unsigned chars I thought I'd print that as is.
Unfortunately, the following is my output:
��.�#a��%Ćw�0��
which, according to sizeof() is 8 bytes long.
How do I convert that to a readable format?
Thanks in advance!
PS:
Output should look like this:
1c0143c6ac7505c8866d10270a480dec
Firstly, sizeof a pointer will give the size of a pointer to char, which is the size of a word in your machine (I suppose it’s 64-bit, since your size returned 8). Pointers do not carry information of the size of the pointer, you’d have to return it elsewhere.
Anyway, since you know that a MD5 digest has 16 bytes, you can just iterate over each of them and print each byte in a more readable format using sprintf. Something like that:
for (int i = 0; i < 16; i++)
printf("%02x", (int)(unsigned char)digest[i]);
putchar('\n');
If you want to print it to a file, change printf to fprintf and putchar to fputc (the arguments change a bit however).
To put it into a string, you’d have to sprint each byte in the correct position of the string, something like this:
char* str = malloc(33 * sizeof(char));
for (int i = 0; i < 16; i++)
sprintf(str+2*i, "%02x", (int)(unsigned char)digest[i]);
P.S: don’t forget to free everything after.
There is no guarantee that your hashfunc is going to produce printable ASCII strings. In theory since they are really just binary data they could have embedded 0s which will screw up all the normal string handling functions anyway.
Best bet is to print each unsigned char as an unsigned char via a for loop.
void printhash(unsigned char* hash)
{
for(int i = 0; i < 16; i++)
{
printf("%02x", hash[i]);
}
printf("\n");
}
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.
#include <stdio.h>
int main ()
{
char *ptr = "stackoverflow"
}
Is there any way to find the length of stackoverflow pointed by ptr, as sizeof ptr always gives 4
Use strlen to find the length of (number of characters in) a string
const char *ptr = "stackoverflow";
size_t length = strlen(ptr);
Another minor point, note that ptr is a string literal (a pointer to const memory which cannot be modified). Its better practice to declare it as const to show this.
sizeof() returns the size required by the type. Since the type you pass to sizeof in this case is a pointer, it will return size of the pointer.
If you need the size of the data pointed by a pointer you will have to remember it by storing it explicitly.
sizeof() works at compile time. so, sizeof(ptr) will return 4 or 8 bytes typically. Instead use strlen.
The strlen() function provided by string.h gives you how many "real characters" the string pointed by the argument contains. However, this length does not include the terminating null character '\0'; you have to consider it if you need the length to allocate memory.
That 4 bytes is the size of a pointer to char on your platform.
#include<stdio.h>
main()
{
int mystrlen(char *);
char str[100];
char *p;
p=str;
printf("Enter the string..?\n");
scanf("%s",p);
int x=mystrlen(p);
printf("Length of string is=%d\n",x);
}
int mystrlen(char *p)
{
int c=0;
while(*p!='\0')
{
c++;
*p++;
}
return(c);
}
simple code to understand
You are looking for the strlen() function.
You can try using:
char *ptr = "stackoverflow"
size_t len = strlen(ptr);
if ptr length is an argument of a function it's reasonable to use pointers as a strings. we can get string length by following code:
char *ptr = "stackoverflow";
length=strlen((const char *)ptr);
And for more explanation, if string is an input string by user with variable length, we can use following code:
unsigned char *ptr;
ptr=(unsigned char *)calloc(50, sizeof(unsigned char));
scanf("%s",ptr );
length=strlen((const char *)ptr);
Purely using pointers you can use pointer arithmetic:
int strLen(char *s)
{
int *p = s;
while(*p !=’\0’)
{
p++; /* increase the address until the end */
}
Return p – s; /* Subtract the two addresses, end - start */
}
Even though this is a generic C question, it gets pretty high hits when looking this question up for C++. Not only was I in C/C++ territory, I also had to be mindful of Microsoft's Security Development Lifecycle (SDL) Banned Function Calls for a specific project which made strlen a no-go due to,
For critical applications, such as those accepting anonymous Internet connections, strlen must also be replaced...
Anyway, this answer is basically just a twist on the answers from the others but with approved Microsoft C++ alternative function calls and considerations for wide-character handling in respect to C99's updated limit of 65,535 bytes.
#include <iostream>
#include <Windows.h>
int wmain()
{
// 1 byte per char, 65535 byte limit per C99 updated standard
// https://stackoverflow.com/a/5351964/3543437
const size_t ASCII_ARRAY_SAFE_SIZE_LIMIT = 65535;
// Theoretical UTF-8 upper byte limit of 6; can typically use 16383 for 4 bytes per char instead:
// https://stijndewitt.com/2014/08/09/max-bytes-in-a-utf-8-char/
const size_t UNICODE_ARRAY_SAFE_SIZE_LIMIT = 10922;
char ascii_array[] = "ACSCII stuff like ABCD1234.";
wchar_t unicode_array[] = L"Unicode stuff like → ∞ ∑ Σὲ γνωρίζω τὴν ደሀ ᚦᚫᛏ.";
char * ascii_array_ptr = &ascii_array[0];
wchar_t * unicode_array_ptr = &unicode_array[0];
std::cout << "The string length of the char array is: " << strnlen_s(ascii_array_ptr, ASCII_ARRAY_SAFE_SIZE_LIMIT) << std::endl;
std::wcout << L"The string length of the wchar_t array is: " << wcsnlen_s(unicode_array_ptr, UNICODE_ARRAY_SAFE_SIZE_LIMIT) << std::endl;
return 0;
}
Output:
The string length of the char array is: 27
The string length of the wchar_t array is: 47
strlen() gives you the exact length of the string [excluding '\0']
sizeof() gives you the size of the data type used.
// stackoverflow = 13 Characters
const char* ptr = "stackoverflow";
strlen(ptr); // 13 bytes - exact size (NOT includes '\0')
sizeof(ptr); // 4 bytes - Size of integer pointer used by the platform
sizeof(*ptr); // 1 byte - Size of char data type
strlen("stackoverflow"); // 13 bytes - exact size
sizeof("stackoverflow"); // 14 bytes - includes '\0'
#include<stdio.h>
int main() {
char *pt = "String of pointer";
int i = 0;
while (*pt != '\0') {
i++;
pt++;
}
printf("Length of String : %d", i);
return 0;
}
We can also use strlen() function or sizeof() operator which is builtin in C.
We can also take help of pointer arithmetic as above example.