使用 sprintf() 函数后 C 字符字符串不可读
C char string not readable after using sprintf() function
在 Arduino Sketch 上,我需要使用 C 字符串而不是 C++ 字符串对象,以最大限度地减少内存使用。这本身就是一个挑战,因为我不熟悉经典 C。
然而不知何故我让它工作(或多或少)但我遇到了问题。这是一个测试草图来解释它:
#define APIKEY "TWITTER_KEY" // api key ThingSpeak
#define TARGET_IP "184.106.153.149"/// //local direccion IP o Hosting ThingSpeak
#define TARGET_PORT "80" /// puerto 80
#define ID "WiFi_ID" //name of wireless access point to connect to - Red de inhalambrica wifi
#define PASS "WiFI_Password" //wifi password - Contraseña de Wifi
#define TWEET "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
char foo[400]; //contains the tweet request
char bar[20]; //auxiliary
char numberString[3]; //contains numbers
void setup() {
Serial.begin(9600);
testMethod();
}
void testMethod(){
Serial.println(" ");
Serial.println("testMethod");
Serial.println(" ");
strcpy(foo, "api_key=");
strcat(foo, APIKEY);
strcat(foo, "&status=");
strcat(foo, TWEET);
Serial.println(foo);
//sprintf(numberString, "%d", strlen(foo)); //converts the integer into a char
Serial.println(numberString);
// Create HTTP POST Data
strcpy(foo, "POST /apps/thingtweet/1/statuses/update HTTP/1.1\n");
strcat(foo, "Host: api.thingspeak.com\n");
strcat(foo, "Connection: close\n");
strcat(foo, "Content-Type: application/x-www-form-urlencoded\n");
strcat(foo, "Content-Length: ");
strcat(foo, numberString);
strcat(foo, "\n\n");
strcat(foo, "api_key=");
strcat(foo, APIKEY);
strcat(foo, "&status=");
strcat(foo, TWEET);
Serial.println(foo);
}
void loop() {
}
如果我要取消注释行
//sprintf(numberString, "%d", strlen(foo)); //converts the integer into a char
然后我无法在串行监视器上打印 foo
,也无法打印稍后生成的新 foo
。如果我硬编码一个整数而不是 strlen()
函数,情况也是如此。
我会将此描述为一种奇怪的行为,但很可能只是我的无知。我阅读了有关 sprintf()
方法的文档,但我还没有看到有关此问题的任何信息。
任何帮助将不胜感激。
提前致谢!
strlen(foo)
是一个 3 位数字,因此您需要为 numberString
分配 4 个字节以容纳这 3 位数字和 NUL 终止符。
嗯,看来 foo
(顺便说一句,这里的变量名很棒)的长度可以超过 99,所以你需要多于两位数。你知道 C 字符串是以 0 结尾的吗?字符串 "123"
在内存中的表示是:
+-+-+-+--+
|1|2|3|[=10=]|
+-+-+-+--+
其中 [=15=]
是一个值为 0 的 char
。所以总是需要一个额外的位置来保存它。你应该让你的阵列更大:
char numberString[8];
为了安全起见。同样使用 snprintf()
在这里有所帮助:
snprintf(numberString, sizeof numberString, "%zu", strlen(foo));
因为从技术上讲,您也会从类型不匹配中获得未定义的行为(%d
适用于 int
,但 strlen()
returns size_t
).
您为 numberString 保留了 3 个字符。这包括终止零字符。如果 strlen(foo) returns 大于 99 的整数,您将溢出 numberString 缓冲区。缓冲区溢出后可能会发生有趣的事情。
您在 strlen()
上遇到了问题,它没有给出以 null 结尾的字节长度。
char foo[400] = "hello world";
// here you allocated the less width, in C strings are the sequence of character bytes terminated with NULL in the end.
char number[4];
sprintf(number, "value: %zu\n", strlen(foo));
在 Arduino Sketch 上,我需要使用 C 字符串而不是 C++ 字符串对象,以最大限度地减少内存使用。这本身就是一个挑战,因为我不熟悉经典 C。
然而不知何故我让它工作(或多或少)但我遇到了问题。这是一个测试草图来解释它:
#define APIKEY "TWITTER_KEY" // api key ThingSpeak
#define TARGET_IP "184.106.153.149"/// //local direccion IP o Hosting ThingSpeak
#define TARGET_PORT "80" /// puerto 80
#define ID "WiFi_ID" //name of wireless access point to connect to - Red de inhalambrica wifi
#define PASS "WiFI_Password" //wifi password - Contraseña de Wifi
#define TWEET "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
char foo[400]; //contains the tweet request
char bar[20]; //auxiliary
char numberString[3]; //contains numbers
void setup() {
Serial.begin(9600);
testMethod();
}
void testMethod(){
Serial.println(" ");
Serial.println("testMethod");
Serial.println(" ");
strcpy(foo, "api_key=");
strcat(foo, APIKEY);
strcat(foo, "&status=");
strcat(foo, TWEET);
Serial.println(foo);
//sprintf(numberString, "%d", strlen(foo)); //converts the integer into a char
Serial.println(numberString);
// Create HTTP POST Data
strcpy(foo, "POST /apps/thingtweet/1/statuses/update HTTP/1.1\n");
strcat(foo, "Host: api.thingspeak.com\n");
strcat(foo, "Connection: close\n");
strcat(foo, "Content-Type: application/x-www-form-urlencoded\n");
strcat(foo, "Content-Length: ");
strcat(foo, numberString);
strcat(foo, "\n\n");
strcat(foo, "api_key=");
strcat(foo, APIKEY);
strcat(foo, "&status=");
strcat(foo, TWEET);
Serial.println(foo);
}
void loop() {
}
如果我要取消注释行
//sprintf(numberString, "%d", strlen(foo)); //converts the integer into a char
然后我无法在串行监视器上打印 foo
,也无法打印稍后生成的新 foo
。如果我硬编码一个整数而不是 strlen()
函数,情况也是如此。
我会将此描述为一种奇怪的行为,但很可能只是我的无知。我阅读了有关 sprintf()
方法的文档,但我还没有看到有关此问题的任何信息。
任何帮助将不胜感激。 提前致谢!
strlen(foo)
是一个 3 位数字,因此您需要为 numberString
分配 4 个字节以容纳这 3 位数字和 NUL 终止符。
嗯,看来 foo
(顺便说一句,这里的变量名很棒)的长度可以超过 99,所以你需要多于两位数。你知道 C 字符串是以 0 结尾的吗?字符串 "123"
在内存中的表示是:
+-+-+-+--+
|1|2|3|[=10=]|
+-+-+-+--+
其中 [=15=]
是一个值为 0 的 char
。所以总是需要一个额外的位置来保存它。你应该让你的阵列更大:
char numberString[8];
为了安全起见。同样使用 snprintf()
在这里有所帮助:
snprintf(numberString, sizeof numberString, "%zu", strlen(foo));
因为从技术上讲,您也会从类型不匹配中获得未定义的行为(%d
适用于 int
,但 strlen()
returns size_t
).
您为 numberString 保留了 3 个字符。这包括终止零字符。如果 strlen(foo) returns 大于 99 的整数,您将溢出 numberString 缓冲区。缓冲区溢出后可能会发生有趣的事情。
您在 strlen()
上遇到了问题,它没有给出以 null 结尾的字节长度。
char foo[400] = "hello world";
// here you allocated the less width, in C strings are the sequence of character bytes terminated with NULL in the end.
char number[4];
sprintf(number, "value: %zu\n", strlen(foo));